Skill Tracer
Skills › Scientific Agent Skills › matchms › workflows.md

workflows.md

471 lines · skills/matchms/references/workflows.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Practical Workflows (matchms 0.33.1)
2
3These patterns use the current 0.33.1 API. Adapt tolerances and quality filters
4to the instrument, acquisition method, and scientific question.
5

Practical Workflows (matchms 0.33.1)

These patterns use the current 0.33.1 API. Adapt tolerances and quality filters to the instrument, acquisition method, and scientific question.

Raw lines 1 to 5
6## 1. Standard Query/Reference Preprocessing
7
8Apply the same peak processing to both collections. Metadata enrichment can
9differ when a reference library contains known structures and queries do not.
11```python
12from matchms import SpectrumProcessor
13from matchms.filtering import (
14 default_filters,
15 normalize_intensities,
16 require_minimum_number_of_peaks,
17 require_precursor_mz,
18 select_by_mz,
19 select_by_relative_intensity,
21from matchms.importing import load_spectra
24def preprocess(path):
25 raw = [default_filters(spectrum) for spectrum in load_spectra(path)]
26 processor = SpectrumProcessor(
27 [
28 (require_precursor_mz, {"minimum_accepted_mz": 50.0}),
29 normalize_intensities,
30 (select_by_mz, {"mz_from": 20.0, "mz_to": 1500.0}),
31 (select_by_relative_intensity, {"intensity_from": 0.01}),
32 (require_minimum_number_of_peaks, {"n_required": 5}),
33 ]
34 )
35 cleaned, _ = processor.process_spectra(
36 raw,
37 progress_bar=False,
38 create_report=False,
39 )
40 return cleaned, ["default_filters", *processor.processing_steps]
43queries, query_steps = preprocess("queries.mgf")
44references, reference_steps = preprocess("library.msp")
45assert query_steps == reference_steps
46```
48`SpectrumProcessor` may reorder built-in filters. Persist the final
49`processing_steps`, not only the requested list. Run the aggregate
50`default_filters` before the processor; if passed as one callable, it is treated
51as a custom filter and placed after registered filters.

1. Standard Query/Reference Preprocessing

Apply the same peak processing to both collections. Metadata enrichment can differ when a reference library contains known structures and queries do not.

from matchms import SpectrumProcessor
from matchms.filtering import (
    default_filters,
    normalize_intensities,
    require_minimum_number_of_peaks,
    require_precursor_mz,
    select_by_mz,
    select_by_relative_intensity,
)
from matchms.importing import load_spectra


def preprocess(path):
    raw = [default_filters(spectrum) for spectrum in load_spectra(path)]
    processor = SpectrumProcessor(
        [
            (require_precursor_mz, {"minimum_accepted_mz": 50.0}),
            normalize_intensities,
            (select_by_mz, {"mz_from": 20.0, "mz_to": 1500.0}),
            (select_by_relative_intensity, {"intensity_from": 0.01}),
            (require_minimum_number_of_peaks, {"n_required": 5}),
        ]
    )
    cleaned, _ = processor.process_spectra(
        raw,
        progress_bar=False,
        create_report=False,
    )
    return cleaned, ["default_filters", *processor.processing_steps]


queries, query_steps = preprocess("queries.mgf")
references, reference_steps = preprocess("library.msp")
assert query_steps == reference_steps

SpectrumProcessor may reorder built-in filters. Persist the final processing_steps, not only the requested list. Run the aggregate default_filters before the processor; if passed as one callable, it is treated as a custom filter and placed after registered filters.

Raw lines 6 to 52
53## 2. Run the Bundled Library Search
55The bundled CLI is the fastest route to a reproducible CSV:
57```bash
58uv run python scripts/library_search.py \
59 queries.mgf library.msp hits.csv \
60 --metric modified \
61 --tolerance 0.02 \
62 --top-k 10 \
63 --min-score 0.6 \
64 --min-matches 5
65```
67The script:
69- applies the same configurable peak filters to both inputs;
70- supports cosine, exact/greedy modified cosine, neutral-loss, BLINK, and Flash
71 modes;
72- handles both scalar and structured matchms score records;
73- rejects non-finite numeric settings and invalid/nonpositive precursors when
74 the selected operation needs them;
75- applies the requested relative-intensity cutoff inside Flash as well;
76- records identifiers, precursor m/z, rank, score, and matched peaks;
77- refuses pickle inputs;
78- refuses to overwrite output unless `--force`; and
79- stops before an unexpectedly large pairwise matrix unless `--max-pairs` is
80 explicitly raised.
82Use `--help` before batch use.

2. Run the Bundled Library Search

The bundled CLI is the fastest route to a reproducible CSV:

uv run python scripts/library_search.py \
  queries.mgf library.msp hits.csv \
  --metric modified \
  --tolerance 0.02 \
  --top-k 10 \
  --min-score 0.6 \
  --min-matches 5

The script:

  • applies the same configurable peak filters to both inputs;
  • supports cosine, exact/greedy modified cosine, neutral-loss, BLINK, and Flash modes;
  • handles both scalar and structured matchms score records;
  • rejects non-finite numeric settings and invalid/nonpositive precursors when the selected operation needs them;
  • applies the requested relative-intensity cutoff inside Flash as well;
  • records identifiers, precursor m/z, rank, score, and matched peaks;
  • refuses pickle inputs;
  • refuses to overwrite output unless --force; and
  • stops before an unexpectedly large pairwise matrix unless --max-pairs is explicitly raised.

Use --help before batch use.

Raw lines 53 to 83
Runs code python scripts/library_search.py :58
84## 3. Programmatic Spectral-Library Search
86```python
87from matchms import calculate_scores
88from matchms.similarity import ModifiedCosineGreedy
90metric = ModifiedCosineGreedy(tolerance=0.02)
91scores = calculate_scores(
92 references=references,
93 queries=queries,
94 similarity_function=metric,
97score_name = "ModifiedCosineGreedy_score"
98matches_name = "ModifiedCosineGreedy_matches"
99rows = []
101for query_index, query in enumerate(queries):
102 ranked = scores.scores_by_query(query, name=score_name, sort=True)
103 for rank, (reference, value) in enumerate(ranked[:10], start=1):
104 rows.append(
105 {
106 "query_index": query_index,
107 "query_id": query.get("spectrum_id", query.get("id")),
108 "reference_id": reference.get(
109 "spectrum_id",
110 reference.get("compound_name"),
111 ),
112 "rank": rank,
113 "score": float(value[score_name]),
114 "matches": int(value[matches_name]),
115 }
116 )
117```
119Filter on both score and matched peaks only after examining their distributions.
120Do not label arbitrary cutoffs as universal high/medium/low confidence.

3. Programmatic Spectral-Library Search

from matchms import calculate_scores
from matchms.similarity import ModifiedCosineGreedy

metric = ModifiedCosineGreedy(tolerance=0.02)
scores = calculate_scores(
    references=references,
    queries=queries,
    similarity_function=metric,
)

score_name = "ModifiedCosineGreedy_score"
matches_name = "ModifiedCosineGreedy_matches"
rows = []

for query_index, query in enumerate(queries):
    ranked = scores.scores_by_query(query, name=score_name, sort=True)
    for rank, (reference, value) in enumerate(ranked[:10], start=1):
        rows.append(
            {
                "query_index": query_index,
                "query_id": query.get("spectrum_id", query.get("id")),
                "reference_id": reference.get(
                    "spectrum_id",
                    reference.get("compound_name"),
                ),
                "rank": rank,
                "score": float(value[score_name]),
                "matches": int(value[matches_name]),
            }
        )

Filter on both score and matched peaks only after examining their distributions. Do not label arbitrary cutoffs as universal high/medium/low confidence.

Raw lines 84 to 121
122## 4. Efficient Precursor-Gated Search
124For identity-oriented search, a precursor gate can reduce expensive spectral
125calculations:
127```python
128from matchms import calculate_scores
129from matchms.similarity import ModifiedCosineGreedy, PrecursorMzMatch
131scores = calculate_scores(
132 references,
133 queries,
134 PrecursorMzMatch(tolerance=10, tolerance_type="ppm"),
135 array_type="sparse",
137scores.filter_by_range(
138 name="PrecursorMzMatch",
139 low=0.5,
140 above_operator=">=",
142if len(scores.scores.row) == 0:
143 raise ValueError("No candidates passed the precursor gate")
144scores.calculate(
145 ModifiedCosineGreedy(tolerance=0.02),
146 array_type="sparse",
147 join_type="left",
149```
151This restricts computation to retained coordinates only when fewer than half
152of all pairs remain and the join is left/inner. Otherwise matchms 0.33.1
153computes the full matrix before joining; a 1-by-1 input always uses `pair()`.
154Stop when no candidates remain. This gate is inappropriate for broad analog
155discovery across precursor shifts or adducts.

4. Efficient Precursor-Gated Search

For identity-oriented search, a precursor gate can reduce expensive spectral calculations:

from matchms import calculate_scores
from matchms.similarity import ModifiedCosineGreedy, PrecursorMzMatch

scores = calculate_scores(
    references,
    queries,
    PrecursorMzMatch(tolerance=10, tolerance_type="ppm"),
    array_type="sparse",
)
scores.filter_by_range(
    name="PrecursorMzMatch",
    low=0.5,
    above_operator=">=",
)
if len(scores.scores.row) == 0:
    raise ValueError("No candidates passed the precursor gate")
scores.calculate(
    ModifiedCosineGreedy(tolerance=0.02),
    array_type="sparse",
    join_type="left",
)

This restricts computation to retained coordinates only when fewer than half of all pairs remain and the join is left/inner. Otherwise matchms 0.33.1 computes the full matrix before joining; a 1-by-1 input always uses pair(). Stop when no candidates remain. This gate is inappropriate for broad analog discovery across precursor shifts or adducts.

Raw lines 122 to 156
157## 5. Reproducible `Pipeline` Workflow
159`Pipeline` combines import, ordered filtering, sparse score gating, and score
160calculation. A workflow can also be written to YAML.
162```python
163from matchms import Pipeline
164from matchms.Pipeline import create_workflow
166common_filters = [
167 "make_charge_int",
168 "add_compound_name",
169 "derive_adduct_from_name",
170 "derive_formula_from_name",
171 "clean_compound_name",
172 "interpret_pepmass",
173 "add_precursor_mz",
174 "derive_ionmode",
175 "correct_charge",
176 ["require_precursor_mz", {"minimum_accepted_mz": 50.0}],
177 "normalize_intensities",
178 ["select_by_relative_intensity", {"intensity_from": 0.01}],
179 ["require_minimum_number_of_peaks", {"n_required": 5}],
182workflow = create_workflow(
183 yaml_file_name=None,
184 query_filters=common_filters,
185 reference_filters=common_filters,
186 score_computations=[
187 ["precursormzmatch", {"tolerance": 10, "tolerance_type": "ppm"}],
188 ["filter_by_range", {"name": "PrecursorMzMatch", "low": 0.5}],
189 ["modifiedcosinegreedy", {"tolerance": 0.02}],
190 [
191 "filter_by_range",
192 {"name": "ModifiedCosineGreedy_score", "low": 0.6},
193 ],
194 ],
197pipeline = Pipeline(
198 workflow,
199 progress_bar=False,
200 logging_level="WARNING",
201 logging_file="matchms-pipeline.log",
203pipeline.run(
204 query_files="queries.mgf",
205 reference_files="library.msp",
206 cleaned_query_file="queries-cleaned.mgf",
207 cleaned_reference_file="library-cleaned.msp",
208 create_report=False,
210scores = pipeline.scores
211```
213Notes:
215- `create_workflow()` expects matchms filter callables/names and score class
216 names lowercased in `score_computations`.
217- The first score should establish the coordinate set when later metrics should
218 be candidate-gated.
219- `filter_by_range` mutates the retained coordinates.
220- `Pipeline.run()` stores final scores on `pipeline.scores`.
221- Output and YAML paths must not already exist.
222- For all-vs-all scoring, omit `reference_files`; Pipeline then sets symmetric
223 mode.
225To persist and reload a workflow:
227```python
228from matchms import Pipeline
229from matchms.Pipeline import create_workflow
230from matchms.yaml_file_functions import load_workflow_from_yaml_file
232create_workflow(
233 yaml_file_name="workflow.yaml",
234 query_filters=common_filters,
235 reference_filters=common_filters,
236 score_computations=[["cosinegreedy", {"tolerance": 0.02}]],
239workflow = load_workflow_from_yaml_file("workflow.yaml")
240Pipeline(workflow).run("queries.mgf", "library.msp")
241```
243Treat YAML as configuration, not as a substitute for recording software and
244input versions.

5. Reproducible Pipeline Workflow

Pipeline combines import, ordered filtering, sparse score gating, and score calculation. A workflow can also be written to YAML.

from matchms import Pipeline
from matchms.Pipeline import create_workflow

common_filters = [
    "make_charge_int",
    "add_compound_name",
    "derive_adduct_from_name",
    "derive_formula_from_name",
    "clean_compound_name",
    "interpret_pepmass",
    "add_precursor_mz",
    "derive_ionmode",
    "correct_charge",
    ["require_precursor_mz", {"minimum_accepted_mz": 50.0}],
    "normalize_intensities",
    ["select_by_relative_intensity", {"intensity_from": 0.01}],
    ["require_minimum_number_of_peaks", {"n_required": 5}],
]

workflow = create_workflow(
    yaml_file_name=None,
    query_filters=common_filters,
    reference_filters=common_filters,
    score_computations=[
        ["precursormzmatch", {"tolerance": 10, "tolerance_type": "ppm"}],
        ["filter_by_range", {"name": "PrecursorMzMatch", "low": 0.5}],
        ["modifiedcosinegreedy", {"tolerance": 0.02}],
        [
            "filter_by_range",
            {"name": "ModifiedCosineGreedy_score", "low": 0.6},
        ],
    ],
)

pipeline = Pipeline(
    workflow,
    progress_bar=False,
    logging_level="WARNING",
    logging_file="matchms-pipeline.log",
)
pipeline.run(
    query_files="queries.mgf",
    reference_files="library.msp",
    cleaned_query_file="queries-cleaned.mgf",
    cleaned_reference_file="library-cleaned.msp",
    create_report=False,
)
scores = pipeline.scores

Notes:

  • create_workflow() expects matchms filter callables/names and score class names lowercased in score_computations.
  • The first score should establish the coordinate set when later metrics should be candidate-gated.
  • filter_by_range mutates the retained coordinates.
  • Pipeline.run() stores final scores on pipeline.scores.
  • Output and YAML paths must not already exist.
  • For all-vs-all scoring, omit reference_files; Pipeline then sets symmetric mode.

To persist and reload a workflow:

from matchms import Pipeline
from matchms.Pipeline import create_workflow
from matchms.yaml_file_functions import load_workflow_from_yaml_file

create_workflow(
    yaml_file_name="workflow.yaml",
    query_filters=common_filters,
    reference_filters=common_filters,
    score_computations=[["cosinegreedy", {"tolerance": 0.02}]],
)

workflow = load_workflow_from_yaml_file("workflow.yaml")
Pipeline(workflow).run("queries.mgf", "library.msp")

Treat YAML as configuration, not as a substitute for recording software and input versions.

Raw lines 157 to 245
246## 6. All-vs-All Comparison
248```python
249from matchms import calculate_scores
250from matchms.similarity import CosineGreedy
252scores = calculate_scores(
253 references=spectra,
254 queries=spectra,
255 similarity_function=CosineGreedy(tolerance=0.02),
256 array_type="sparse",
257 is_symmetric=True,
259```
261`is_symmetric=True` permits implementations to avoid redundant calculation;
262Flash 0.33.1 does not exploit this flag for runtime savings. The
263logical pair count still grows quadratically. Estimate size before launching:
265```python
266n = len(spectra)
267unique_pairs_with_diagonal = n * (n + 1) // 2
268```
270For large collections, consider:
272- precursor/metadata candidate masks;
273- `BlinkCosine` or matrix-oriented `FlashSimilarity`;
274- batched query subsets;
275- sparse score thresholds; and
276- approximate-neighbor indexing with validated recall.
278Do not densify a large result with `to_array()` merely to find top hits.

6. All-vs-All Comparison

from matchms import calculate_scores
from matchms.similarity import CosineGreedy

scores = calculate_scores(
    references=spectra,
    queries=spectra,
    similarity_function=CosineGreedy(tolerance=0.02),
    array_type="sparse",
    is_symmetric=True,
)

is_symmetric=True permits implementations to avoid redundant calculation; Flash 0.33.1 does not exploit this flag for runtime savings. The logical pair count still grows quadratically. Estimate size before launching:

n = len(spectra)
unique_pairs_with_diagonal = n * (n + 1) // 2

For large collections, consider:

  • precursor/metadata candidate masks;
  • BlinkCosine or matrix-oriented FlashSimilarity;
  • batched query subsets;
  • sparse score thresholds; and
  • approximate-neighbor indexing with validated recall.

Do not densify a large result with to_array() merely to find top hits.

Raw lines 246 to 279
280## 7. Fast Matrix Scoring

7. Fast Matrix Scoring

Raw lines 280 to 281
282### Flash entropy
284```python
285from matchms import calculate_scores
286from matchms.similarity import FlashSimilarity
288scores = calculate_scores(
289 references,
290 queries,
291 FlashSimilarity(
292 score_type="spectral_entropy",
293 matching_mode="fragment",
294 tolerance=0.02,
295 noise_cutoff=0.01,
296 ),
298```

Flash entropy

from matchms import calculate_scores
from matchms.similarity import FlashSimilarity

scores = calculate_scores(
    references,
    queries,
    FlashSimilarity(
        score_type="spectral_entropy",
        matching_mode="fragment",
        tolerance=0.02,
        noise_cutoff=0.01,
    ),
)
Raw lines 282 to 299
300### Fast modified-cosine-like mode
302```python
303scores = calculate_scores(
304 references,
305 queries,
306 FlashSimilarity(
307 score_type="cosine",
308 matching_mode="hybrid",
309 tolerance=0.02,
310 ),
312```
314Flash outputs a scalar `FlashSimilarity` field without a matched-peak count.
315Validate ranking agreement against a transparent baseline on representative
316data. Flash allocates a dense matrix even when sparse output is requested.

Fast modified-cosine-like mode

scores = calculate_scores(
    references,
    queries,
    FlashSimilarity(
        score_type="cosine",
        matching_mode="hybrid",
        tolerance=0.02,
    ),
)

Flash outputs a scalar FlashSimilarity field without a matched-peak count. Validate ranking agreement against a transparent baseline on representative data. Flash allocates a dense matrix even when sparse output is requested.

Raw lines 300 to 317
318## 8. Mirror-Plot Validation
320```python
321from pathlib import Path
323output = Path("top-hit-mirror.png")
324figure, axis = query.plot_against(reference, figsize=(10, 6), dpi=200)
325figure.savefig(output, bbox_inches="tight")
326```
328Inspect:
330- unshifted and shifted matched peaks;
331- precursor and adduct agreement;
332- whether the score is driven by one dominant fragment;
333- unexplained high-intensity peaks; and
334- collision-energy/acquisition differences.

8. Mirror-Plot Validation

from pathlib import Path

output = Path("top-hit-mirror.png")
figure, axis = query.plot_against(reference, figsize=(10, 6), dpi=200)
figure.savefig(output, bbox_inches="tight")

Inspect:

  • unshifted and shifted matched peaks;
  • precursor and adduct agreement;
  • whether the score is driven by one dominant fragment;
  • unexplained high-intensity peaks; and
  • collision-energy/acquisition differences.
Raw lines 318 to 335
336## 9. Spectral Similarity Network
338Networks require an all-vs-all `Scores` object and a unique identifier on each
339spectrum:
341```python
342from matchms import calculate_scores
343from matchms.networking import SimilarityNetwork
344from matchms.similarity import ModifiedCosineGreedy
346scores = calculate_scores(
347 spectra,
348 spectra,
349 ModifiedCosineGreedy(tolerance=0.02),
350 array_type="sparse",
351 is_symmetric=True,
354ids = [s.get("spectrum_id") for s in spectra]
355assert all(isinstance(value, str) and value for value in ids)
356assert len(ids) == len(set(ids))
358network = SimilarityNetwork(
359 identifier_key="spectrum_id",
360 top_n=20,
361 max_links=10,
362 score_cutoff=0.7,
363 link_method="mutual",
364 keep_unconnected_nodes=True,
366network.create_network(
367 scores,
368 score_name="ModifiedCosineGreedy_score",
370network.export_to_file("spectral-network.graphml", graph_format="graphml")
371```
373Supported export formats include GraphML, GEXF, GML, Cytoscape JSON, and JSON.
374`top_n` must be at least `max_links`. `max_links` limits outgoing additions per
375iteration, not total node degree (incoming links can increase it). Use unique
376nonempty string IDs: numeric IDs can become mixed integer/string nodes.
377Equal scores near the strict link limit
378can make tie selection order-dependent; use deterministic identifiers and
379document parameters.
381Network components are hypotheses about spectral relatedness, not proof of
382shared structure or biosynthetic origin.

9. Spectral Similarity Network

Networks require an all-vs-all Scores object and a unique identifier on each spectrum:

from matchms import calculate_scores
from matchms.networking import SimilarityNetwork
from matchms.similarity import ModifiedCosineGreedy

scores = calculate_scores(
    spectra,
    spectra,
    ModifiedCosineGreedy(tolerance=0.02),
    array_type="sparse",
    is_symmetric=True,
)

ids = [s.get("spectrum_id") for s in spectra]
assert all(isinstance(value, str) and value for value in ids)
assert len(ids) == len(set(ids))

network = SimilarityNetwork(
    identifier_key="spectrum_id",
    top_n=20,
    max_links=10,
    score_cutoff=0.7,
    link_method="mutual",
    keep_unconnected_nodes=True,
)
network.create_network(
    scores,
    score_name="ModifiedCosineGreedy_score",
)
network.export_to_file("spectral-network.graphml", graph_format="graphml")

Supported export formats include GraphML, GEXF, GML, Cytoscape JSON, and JSON. top_n must be at least max_links. max_links limits outgoing additions per iteration, not total node degree (incoming links can increase it). Use unique nonempty string IDs: numeric IDs can become mixed integer/string nodes. Equal scores near the strict link limit can make tie selection order-dependent; use deterministic identifiers and document parameters.

Network components are hypotheses about spectral relatedness, not proof of shared structure or biosynthetic origin.

Raw lines 336 to 383
384## 10. Structure Versus Spectrum Similarity
386Use separate labels and outputs:
388- spectral similarity compares measured peak patterns;
389- fingerprint similarity compares known molecular structures;
390- correlation between the two can be analyzed only where reliable structures
391 are available.
393Do not include a query's true structure in candidate ranking when evaluating a
394spectral identification method; that leaks the answer.

10. Structure Versus Spectrum Similarity

Use separate labels and outputs:

  • spectral similarity compares measured peak patterns;
  • fingerprint similarity compares known molecular structures;
  • correlation between the two can be analyzed only where reliable structures are available.

Do not include a query's true structure in candidate ranking when evaluating a spectral identification method; that leaks the answer.

Raw lines 384 to 395
396## 11. USI-Based Reproducible Pair
398```python
399from matchms.importing import load_from_usi
400from matchms.filtering import default_filters, normalize_intensities
401from matchms.similarity import CosineGreedy
403reference = load_from_usi(
404 "mzspec:GNPS:GNPS-LIBRARY:accession:CCMSLIB00000424840"
406query = load_from_usi(
407 "mzspec:MSV000086109:BD5_dil2x_BD5_01_57213:scan:760"
409if reference is None or query is None:
410 raise ValueError("The USI resolver returned no usable spectrum")
411reference = normalize_intensities(default_filters(reference))
412query = normalize_intensities(default_filters(query))
413result = CosineGreedy(tolerance=0.02).pair(reference, query)
414```
416Record resolver, retrieval date, and returned metadata. A USI is stable
417provenance, but resolver availability and returned annotations can change.

11. USI-Based Reproducible Pair

from matchms.importing import load_from_usi
from matchms.filtering import default_filters, normalize_intensities
from matchms.similarity import CosineGreedy

reference = load_from_usi(
    "mzspec:GNPS:GNPS-LIBRARY:accession:CCMSLIB00000424840"
)
query = load_from_usi(
    "mzspec:MSV000086109:BD5_dil2x_BD5_01_57213:scan:760"
)
if reference is None or query is None:
    raise ValueError("The USI resolver returned no usable spectrum")
reference = normalize_intensities(default_filters(reference))
query = normalize_intensities(default_filters(query))
result = CosineGreedy(tolerance=0.02).pair(reference, query)

Record resolver, retrieval date, and returned metadata. A USI is stable provenance, but resolver availability and returned annotations can change.

Raw lines 396 to 418
419## 12. Provenance Record
421At minimum, save:
423```python
424import json
425import platform
427import matchms
429provenance = {
430 "matchms_version": matchms.__version__,
431 "python_version": platform.python_version(),
432 "query_files": ["queries.mgf"],
433 "reference_files": ["library.msp"],
434 "metadata_harmonization": True,
435 "processing_steps": query_steps,
436 "similarity": {
437 "class": "ModifiedCosineGreedy",
438 "tolerance_da": 0.02,
439 },
440 "selection": {
441 "top_k": 10,
442 "minimum_score": 0.6,
443 "minimum_matches": 5,
444 },
447with open("provenance.json", "w", encoding="utf-8") as handle:
448 json.dump(provenance, handle, indent=2, default=str)
449```
451Also retain input checksums, library release/date, acquisition information,
452code/configuration, and any manual curation decisions.

12. Provenance Record

At minimum, save:

import json
import platform

import matchms

provenance = {
    "matchms_version": matchms.__version__,
    "python_version": platform.python_version(),
    "query_files": ["queries.mgf"],
    "reference_files": ["library.msp"],
    "metadata_harmonization": True,
    "processing_steps": query_steps,
    "similarity": {
        "class": "ModifiedCosineGreedy",
        "tolerance_da": 0.02,
    },
    "selection": {
        "top_k": 10,
        "minimum_score": 0.6,
        "minimum_matches": 5,
    },
}

with open("provenance.json", "w", encoding="utf-8") as handle:
    json.dump(provenance, handle, indent=2, default=str)

Also retain input checksums, library release/date, acquisition information, code/configuration, and any manual curation decisions.

Raw lines 419 to 453
454## Failure Modes
456- **No modified-cosine results:** check precursor m/z after harmonization and
457 filtering.
458- **Unexpected `TypeError` from `SpectrumProcessor`:** call
459 `process_spectrum()`/`process_spectra()`; the processor is not callable.
460- **Cannot format a score as float:** extract a named field from the structured
461 score record.
462- **Top-hit value treated as an index:** `scores_by_query()` returns a Spectrum.
463- **Huge memory use:** avoid dense conversion; gate candidates and estimate pair
464 count.
465- **No network edges:** verify identifier fields, score layer name, threshold,
466 and that the scores are all-vs-all.
467- **Fingerprint warnings:** migrate from `add_fingerprint()` to `Fingerprints`
468 and bridge to the current `FingerprintSimilarity` only when required.
469- **Output already exists:** matchms intentionally refuses overwrite in generic
470 writers and pipeline outputs; choose a new path or replace the intended output
471 when the user has authorized it.

Failure Modes

  • No modified-cosine results: check precursor m/z after harmonization and filtering.
  • **Unexpected TypeError from SpectrumProcessor:** call process_spectrum()/process_spectra(); the processor is not callable.
  • Cannot format a score as float: extract a named field from the structured score record.
  • Top-hit value treated as an index: scores_by_query() returns a Spectrum.
  • Huge memory use: avoid dense conversion; gate candidates and estimate pair count.
  • No network edges: verify identifier fields, score layer name, threshold, and that the scores are all-vs-all.
  • Fingerprint warnings: migrate from add_fingerprint() to Fingerprints and bridge to the current FingerprintSimilarity only when required.
  • Output already exists: matchms intentionally refuses overwrite in generic writers and pipeline outputs; choose a new path or replace the intended output when the user has authorized it.
Raw lines 454 to 471