An end-to-end pipeline for building a comprehensive protein database and performing metaproteomic database searches.
- 1. Data Acquisition
- 2. Source-Specific Preprocessing
- 3. Gene Prediction
- 4. Functional Annotation
- 5. Database Construction
- 6. Metaproteomic Database Search
- 7. References
cFMD data can be downloaded both from Zenodo (https://zenodo.org/records/13285428) and GitHub (https://github.com/SegataLab/cFMD.git)
MiFoDB data can be downloaded from Zenodo (https://zenodo.org/records/10881265)
MGnify data can be downloaded from their website (https://www.ebi.ac.uk/metagenomics)
Uniprot data can be downloaded with the script: uniprot_search.py
python uniprot_search.py
python uniprot_search.py --output-dir ./data/uniprotNotes
- The primary categorical framework of this study is structured around cFMD data.
- From MGnify studies, only contig files belonging to the following categories were downloaded: dairy, fermented_beverages, and fermented_vegetables
- Duplicate studies across cFMD, MiFoDB, and MGnify data sources were identified and removed to ensure data integrity.
- Search parameters for the UniProt database script were configured to align with the metadata parameters of the cFMD dataset.
cFMD and MiFoDB data is already classified into eukaryotic and prokaryotic genomes and requires no additional preprocessing. MGnify need source-specific steps before entering the common analysis pipeline.
MGnify contigs are unclassified and require EukRep for euk/prok separation. For the eukaryotic contigs, organism identity (needed for Augustus model selection) is determined in two steps: MetaEuk easy-predict performs intron-aware protein prediction on the contigs, and MMseqs2 easy-taxonomy then assigns taxonomy to those predicted proteins (amino-acid vs. amino-acid). Running the taxonomy search on predicted proteins rather than on raw contig DNA avoids the frameshift/premature-stop artifacts that a six-frame translated search introduces on intron-containing genomic DNA.
Installing EukRep:
conda create -y -n eukrep -c bioconda python=3.7.16
conda activate eukrep
pip install scikit-learn==0.19.2
pip install EukRepUsing EukRep:
EukRep -i input.fasta -o euk_output.fasta --prokarya prok_output.fastaNotes
- -i: Input FASTA file (metagenomic contigs)
- -o: Output FASTA file for eukaryotic contigs
- --prokarya: Output FASTA file for prokaryotic contigs
Installing SeqKit:
conda install -c bioconda seqkitUsing SeqKit:
seqkit seq -m 1000 euk_output.fasta -o filtered_contigs.fastaNotes
- -m 1000: Minimum length filter (1000 bp in this study); contigs shorter than this are dropped.
- euk_output.fasta: Eukaryotic contigs output from EukRep (input to this step).
- filtered_contigs.fasta: Output file; this is the
filtered_contigs.fastaused as input to MetaEukeasy-predictbelow.
Installing MetaEuk:
conda create -n metaeuk -c conda-forge -c bioconda
conda activate metaeuk
conda install -c conda-forge -c bioconda metaeuk --solver=classicUsing MetaEuk:
metaeuk easy-predict \
filtered_contigs.fasta \
target_db \
output_prefix \
tmp_dir \
--threads 16 \
--split-memory-limit 150GNotes
- filtered_contigs.fasta: Eukaryotic contigs, length-filtered to a minimum length (1000 bp in this study) with
seqkit seq -m 1000before prediction. Short fragments are dropped up front. - target_db: Reference protein database used as evidence for intron-aware prediction (UniRef90 in this study, the same database used for the MMseqs2 taxonomy step below).
- output_prefix: Prefix for output files; predicted proteins are written to
<output_prefix>.fas. - tmp_dir: Temporary directory for intermediate files.
- --threads: Number of CPU threads.
- --split-memory-limit: Maximum memory per split (prevents crashes on large databases).
- The
<output_prefix>.fasprotein file is the input to the MMseqs2 taxonomy step below.
Installing MMseqs2:
conda create -n mmseqs -c conda-forge -c bioconda
conda activate mmseqs
conda install -c conda-forge -c bioconda mmseqs2 --solver=classicUsing MMseqs2:
mmseqs easy-taxonomy predicted_proteins.fas target_db output_prefix tmp_dir \
--threads 16 \
--split 0 \
--split-memory-limit 150G \
--lca-mode 3 \
--search-type 1 \
--tax-lineage 1Notes
- predicted_proteins.fas: Input FASTA file. This is the MetaEuk
easy-predictprotein output (<output_prefix>.fas), NOT the raw eukaryotic contigs — the search is amino-acid vs. amino-acid. - target_db: Reference database for taxonomy assignment (UniRef90 in this study). Must be a taxonomy-enabled MMseqs2 database (i.e. its
<db>_mappingfile must exist). - output_prefix: Prefix for output files (generates _report, _tophit_report, and _lca.tsv).
- tmp_dir: Temporary directory for intermediate files
- --threads: Number of CPU threads
- --split 0: Let MMseqs2 auto-determine the number of splits.
- --split-memory-limit: Maximum memory per split (prevents crashes on large databases)
- --lca-mode 3: LCA algorithm mode: top-hit based approach for taxonomic assignment
- --search-type 1: Amino-acid vs. amino-acid search (the query is predicted protein, not DNA).
- --tax-lineage 1: Write the full lineage string into the output. This is required by the downstream summary step, which parses
_lca.tsvand aggregates taxonomy at the contig level, not the hit level:- Each contig's domain call (Eukaryota/Bacteria/Archaea/Viruses) is decided by majority vote among the domains of its own hits. Domain is matched by literal name in the lineage string rather than by rank-prefix letter, since the prefix used for domain-level entries was inconsistent in practice (e.g.
-_Eukaryotainstead ofd_Eukaryota). - A tied vote at the contig level (equal counts for two domains) is called "Ambiguous" rather than resolved arbitrarily.
- The sample-level domain call is then a majority vote across contigs (one vote per contig, regardless of how many hits that contig produced). This exists specifically to stop a single hit-dense contaminant contig from outvoting many real eukaryotic contigs that each produced only a handful of hits. A tied sample-level vote is also called "Ambiguous".
- phylum/class/genus calls are computed only from hits belonging to contigs already called Eukaryota, so bacterial contamination cannot leak into the genus-level call used for species-model selection downstream.
- Each contig's domain call (Eukaryota/Bacteria/Archaea/Viruses) is decided by majority vote among the domains of its own hits. Domain is matched by literal name in the lineage string rather than by rank-prefix letter, since the prefix used for domain-level entries was inconsistent in practice (e.g.
After preprocessing, all three sources follow the same two-track pipeline: Prodigal + smORFinder for prokaryotic data, Augustus for eukaryotic data. The commands below are run independently for each source (cFMD, MiFoDB, MGnify).
Installing Prodigal:
git clone https://github.com/hyattpd/Prodigal.git
cd ~/Prodigal
make installUsing Prodigal:
prodigal -i input.fasta \
-o output.genes.gbk \
-a output.proteins.faa \
-d output.genes.fna \
-p single -c -mNotes
- -i: Input FASTA file
- -o: Gene coordinates output in GenBank format (.gbk)
- -a: Predicted protein sequences (.faa)
- -d: Predicted gene nucleotide sequences (.fna)
- -p single: Single genome mode (assumes each file is one organism)
- -c: Report only closed (complete) ORFs with both start and stop codons
- -m: Do not include upstream sequence before the start codon
MGnify note: MGnify inputs are unbinned metagenomic contigs, not single genomes, so Prodigal was run in metagenomic mode (
-p meta) instead of-p single. All other flags (-c -m) are unchanged. cFMD and MiFoDB, which are already resolved to per-genome files, use-p singleas shown above.
Installing smORFinder:
conda create -n smorfinder python=3.8.20
conda activate smorfinder
pip install smorfinderUsing smORFinder:
smorf single input.fastaNotes
- single: Single genome mode (one genome per run)
- input.fasta: Input FASTA file (nucleotide sequences)
MGnify note: For the same reason as Prodigal (unbinned contigs rather than single genomes), MGnify was run in metagenomic mode:
smorf meta input.fasta. cFMD and MiFoDB usesmorf singleas shown above.
For cFMD and MiFoDB, organism models are already known. For MGnify, the MMseqs2 results from step 2.1 are used to determine the appropriate species model.
Installing Augustus:
sudo apt install augustus augustus-data augustus-docUsing Augustus:
augustus --species=SPECIES_MODEL \
--strand=both \
--genemodel=complete \
--gff3=on \
--protein=on \
--codingseq=on \
input.fastaNotes
- --species: Augustus species model for gene prediction (e.g., saccharomyces_cerevisiae_S288C, aspergillus_nidulans). Determined by taxonomy mapping (MMseqs2 for MGnify, pre-existing mapping for cFMD/MiFoDB).
- --strand=both: Predict genes on both forward and reverse strands
- --genemodel=complete: Report only complete gene models (with start and stop codons)
- --gff3=on: Output in GFF3 format
- --protein=on: Include predicted protein sequences in the output
- --codingseq=on: Include coding nucleotide sequences in the output
MGnify note: MGnify contigs are fragmentary metagenomic assemblies, so many real genes are truncated by contig ends. Augustus was therefore run with
--genemodel=partialinstead of--genemodel=complete, so that partial genes at contig boundaries are still predicted rather than discarded. All other flags (--strand=both --gff3=on --protein=on --codingseq=onand the taxonomy-derived--speciesmodel) are unchanged. cFMD and MiFoDB use--genemodel=completeas shown above.
Extract protein sequences from GFF output:
perl getAnnoFasta.pl augustus_output.gff3Notes
- augustus_output.gff3: Augustus GFF3 output file containing gene predictions with embedded protein and coding sequences
- outputs: .aa -> Predicted protein sequences (renamed to .faa), .codingseq -> Coding nucleotide sequences (renamed to .cds.fna)
Installing EggNOG-mapper:
conda create -n emapper -c bioconda -c conda-forge python=3.10.19
conda activate emapper
conda install eggnog-mapperInstalling necessary databases:
aria2c -c -x 8 -s 8 -k 1M http://eggnog5.embl.de/download/emapperdb-5.0.2/eggnog.db.gz
aria2c -c -x 8 -s 8 -k 1M http://eggnog5.embl.de/download/emapperdb-5.0.2/eggnog_proteins.dmnd.gz
aria2c -c -x 8 -s 8 -k 1M http://eggnog5.embl.de/download/emapperdb-5.0.2/eggnog.taxa.tar.gzUsing EggNOG-mapper:
emapper.py \
-i input.faa \
-o output_prefix \
--output_dir output_dir \
--data_dir eggnog_db_dir \
--scratch_dir tmp_dir \
--cpu 8 \
-m diamond \
--override \
--dmnd_ignore_warningsNotes
- -i: Input protein FASTA file
- -o: Output file prefix
- --output_dir: Directory for output files
- --data_dir: Path to EggNOG database files (eggnog.db, eggnog_proteins.dmnd, eggnog.taxa.db)
- --scratch_dir: Temporary directory for intermediate files
- --cpu: Number of CPU threads
- -m diamond: Search method: use Diamond for homology search
- --override: Overwrite existing output files
- --dmnd_ignore_warnings: Tolerate ambiguous amino acids (e.g., X) in input sequences
- Created output files: Functional annotation results (GO, KEGG, COG, etc.) -> .emapper.annotations, Diamond search hits -> .emapper.hits, Best matching seed orthologs -> .emapper.seed_orthologs
Three scripts build the FASTA sequence database, its metadata table, and its eggNOG-mapper annotation table. They must be run in order — the metadata and annotation scripts both consume outputs of the FASTA script:
build_fasta_db.py -> build_metadata_db.py
-> build_annotation_db.py
Requirements: pip install openpyxl (used for the Excel reports); .xlsx input
lists additionally need pandas.
All three scripts take the same --list argument: a plain text file (.txt) or
Excel file (.xlsx) where each line / first-column cell is the path to one input
directory. The last component of each path is used as the category name.
/data/results/mgnify/euk/dairy
/data/results/cfmd/prok/fermented_vegetables
/data/results/smorf/dairy
Each script has a clearly-marked configuration block at the top. These encode this project's conventions — edit them if your data differs:
CATEGORY_MAP— merge/rename folder names into one category (e.g.fermented_vegetables→fermented_fruits_and_vegetables). Set to{}for no renaming.HEADER_SEP— the separator inserted between the sample prefix and the original header (__). Must be identical across all three scripts.SUFFIX_TAGS— the recognised file-name tags (proteins,smorf). A file named<sample>.proteins.faayields the prefix<sample>_proteins;<sample>_smorf.faayields<sample>_smorf. Must be identical across all three scripts.parse_path()(inbuild_metadata_db.pyonly) — maps a directory path tosource/cell_type/type. This function encodes the project's exact folder layout; edit it if your tree is different.
Merges all .faa / .faa.gz files per category into one cleaned FASTA, then
merges the categories into a single all_db.faa with cross-category
deduplication. Per-category QC removes empty sequences, headerless sequence
lines, duplicate headers, duplicate sequences (--no-dedup-seqs to disable), and
sequences with invalid amino-acid characters (--no-strip-invalid-aa to
disable). Every header is prefixed as <sample_prefix>__<original_header> so
sequences can be traced back.
Output:
<output_dir>/categories/<category>_db.faa— cleaned per-category DBs<output_dir>/all_db.faa— all categories merged + cross-category dedup<output_dir>/all_db_duplicate_map.tsv—kept_header/merged_header/categorymap (consumed by scripts 02 and 03)<output_dir>/fasta_report.xlsx— numeric report
python build_fasta_db.py --list dirs.txt --output db_out/
python build_fasta_db.py --list dirs.txt --output db_out/ --no-dedup-seqs
python build_fasta_db.py --list dirs.txt --output db_out/ --no-strip-invalid-aaNotes
- Sequence dedup is exact-match on
md5(sequence.upper()), both within and across categories. all_db_duplicate_map.tsvrecords every dropped duplicate (not just the kept one). This is what lets scripts 02/03 lift metadata/annotation to theall_dblevel without losing information for sequences shared across categories.
Derives source / cell_type / type / category from the directory paths
(via parse_path()), matches every header in the cleaned per-category DBs to that
information by prefix, and produces the metadata tables. For sequences that occur
in more than one category, all_db_metadata.tsv writes one row per originating
category for the same kept header (no information is collapsed away).
Output:
<output_dir>/categories/<category>_metadata.tsv<output_dir>/all_metadata.tsv— all per-category rows (original headers)<output_dir>/all_db_metadata.tsv— mapped ontoall_db.faakept headers<output_dir>/metadata_report.xlsx
python build_metadata_db.py --list dirs.txt \
--db db_out/categories \
--dup-map db_out/all_db_duplicate_map.tsv \
--output meta_out/Notes
--dbpoints at thecategories/folder produced by script 01;--dup-mapat itsall_db_duplicate_map.tsv.- smORFinder files carry only "this is a smorf file", not their true origin. The script recovers the real
source/cell_typefrom the sibling_proteinsfile of the same sample; if no sibling is found the record is markedsource=unknownrather than mislabelled. - Header→metadata matching uses a prefix trie, so runtime is independent of the number of prefixes. The join is staged through an on-disk SQLite table to keep memory bounded on large datasets.
Merges eggNOG-mapper .emapper.annotations files per category, prefixing query
IDs to match the FASTA headers, and cleans them (drops rows with the wrong column
count, empty query IDs, duplicate queries, and — when --db is given — queries
with no counterpart in the cleaned DB). It then maps annotations onto all_db.faa
kept headers via the duplicate map.
Output:
<output_dir>/categories/<category>_annotations.tsv<output_dir>/all_db_annotations.tsv— mapped ontoall_db.faakept headers<output_dir>/annotation_report.xlsx
python build_annotation_db.py --list ann_dirs.txt \
--db db_out/categories \
--dup-map db_out/all_db_duplicate_map.tsv \
--output ann_out/Notes
- Assumes eggNOG-mapper v2 output (21 tab-separated columns); adjust
EMAPPER_NCOLS/EMAPPER_HEADERfor other versions. - The
--listhere points at the folders containing.emapper.annotationsfiles (which may differ from the FASTA input folders). - When a sequence shared across categories already has an annotation, further annotations for it are counted as redundant and skipped (not written twice). The report includes an annotation-coverage percentage against
all_db.faa.
Download ProteoWizard MSConvert from https://proteowizard.sourceforge.io/download.html
- We downloaded Pu-erh tea samples from https://www.iprox.cn//page/subproject.html?id=IPX0001388001 that belongs to Zhao et al. (2019).
- We tested two of our databases: all_db and fermented_beverages, and two different databases: a general database prepared from UniProt with uniprot_general_db.py, and a database with metagenomic origin prepared from UniProt with uniprot_metagenomic_db.py.
To prepare uniprot_general database:
python uniprot_general_db.py
python uniprot_general_db.py --output food_db.faa
python uniprot_general_db.py --output food_db.faa --include-unreviewed
python uniprot_general_db.py --chunk-size 30To prepare uniprot_metagenomic database:
python uniprot_metagenomic_db.py
python uniprot_metagenomic_db.py --include-unreviewed
python uniprot_metagenomic_db.py --output custom_name.faaTo convert raw files to mgf files:
Choose your raw files
Select your output format as mgf
On the Filters part: choose Peak Picking
Add the filter and click startSince our databases are too big for MS-GF+, we needed to split them. Download Fasta-File-Splitter from https://github.com/PNNL-Comp-Mass-Spec/Fasta-File-Splitter/releases/.
FastaFileSplitter is a .NET (Windows) program, so on Linux it is run through
Mono. Install Mono first (e.g. sudo apt install mono-runtime on Debian/Ubuntu),
then, in the Fasta-File-Splitter directory:
FastaFileSplitter.exe /I:input.faa /O:./output/ /MB:400Notes
- /I: Input - source .faa / .fasta file path
- /O: Output - directory where split files will be saved
- /MB: Megabytes - split by target file size (since MS-GF+ works with a maximum of 500 MB, we split our database file into 400 MB parts).
Installing MS-GF+:
conda create -n msgf -c bioconda python=3.14.
conda activate msgf
conda install bioconda::msgf_plusBuild Suffix Array (DB indexing):
msgf_plus edu.ucsd.msjava.msdbsearch.BuildSA -d protein_db.fastaNotes
- -d: Protein FASTA database to index
Database Search: Indexes the database before search. Run once per FASTA part.
msgf_plus -s spectra.mgf \
-d protein_db.fasta \
-t 6ppm \
-tda 1 \
-m 1 \
-inst 1 \
-e 1 \
-o results.mzidNotes
- -s: Input spectrum file (MGF format)
- -d: Protein FASTA database
- -t 6ppm: Precursor mass tolerance: 6 ppm
- -tda 1: Target-decoy search: concatenated (automatic decoy generation)
- -m 1: Fragmentation method: CID
- -inst 1: Instrument type: Orbitrap/FTICR/Lumos
- -e 1: Enzyme: Trypsin
- -o: Output file (.mzid format)
To merge mzid files, download the MzidMerger from https://github.com/PNNL-Comp-Mass-Spec/MzidMerger/releases.
Merge split mzid results: Merges per-part mzid files into a single mzid per sample (needed because the database was split into parts).
dotnet MzidMerger.dll \
-inDir mzid_dir \
-filter "sample__db_chunk_*.mzid" \
-out merged.mzidConvert mzid to TSV: Converts mzid output to readable TSV format.
java -Xmx20G -cp MSGFPlus.jar \
edu.ucsd.msjava.ui.MzIDToTsv \
-i input.mzid \
-o output.tsv \
-showDecoy 1Convert TSV files to PSM files:
tsv_to_inference.py: Splits MSGF+ .tsv output into target and decoy PSM files formatted for Percolator input.
python tsv_to_inference.py <input.tsv> <output_dir>For protein inference, we used Py Protein Inference.
conda create -n pyprotein python=3.10
conda activate pyprotein
pip install pyproteininferenceUsage:
protein_inference_cli.py \
-t tmp_dir/sample_target.txt \
-d tmp_dir/sample_decoy.txt \
-y params_inference.yaml \
-l output/sample_inference.csvNotes
- Inference settings are controlled via params_inference.yaml. Key parameters: FDR threshold, parsimony solver, PSM scoring strategy, and decoy symbol.
- Carlino, N., Blanco-Míguez, A., Punčochář, M., Mengoni, C., Pinto, F., Tatti, A., ... & Yap, M. (2024). Unexplored microbial diversity from 2,500 food metagenomes and links with the human microbiome. Cell, 187(20), 5775-5795. Github: https://github.com/SegataLab/cFMD
- Caffrey, E. B., Olm, M. R., Kothe, C. I., Wastyk, H. C., Evans, J. D., & Sonnenburg, J. L. (2025). MiFoDB, a workflow for microbial food metagenomic characterization, enables high-resolution analysis of fermented food microbial dynamics. Msystems, 10(9), e00141-25. Website: https://mifodb.readthedocs.io/en/latest/
- Richardson, L., Allen, B., Baldi, G., Beracochea, M., Bileschi, M. L., Burdett, T., ... & Finn, R. D. (2023). MGnify: the microbiome sequence data analysis resource in 2023. Nucleic acids research, 51(D1), D753-D759. Website: https://www.ebi.ac.uk/metagenomics
- UniProt Consortium. (2019). UniProt: a worldwide hub of protein knowledge. Nucleic acids research, 47(D1), D506-D515.
- West, P. T., Probst, A. J., Grigoriev, I. V., Thomas, B. C., & Banfield, J. F. (2018). Genome-reconstruction for eukaryotes from complex natural microbial communities. Genome research, 28(4), 569-580. Github: https://github.com/patrickwest/EukRep
- Steinegger, M., & Söding, J. (2017). MMseqs2 enables sensitive protein sequence searching for the analysis of massive data sets. Nature biotechnology, 35(11), 1026-1028. Github: https://github.com/soedinglab/mmseqs2
- Levy Karin, E., Mirdita, M., & Söding, J. (2020). MetaEuk—sensitive, high-throughput gene discovery, and annotation for large-scale eukaryotic metagenomics. Microbiome, 8(1), 48. Github: https://github.com/soedinglab/metaeuk
- Shen, W., Sipos, B., & Zhao, L. (2024). SeqKit2: A Swiss army knife for sequence and alignment processing. Imeta, 3(3), e191. Github: https://github.com/shenwei356/seqkit
- Hyatt, D., Chen, G. L., LoCascio, P. F., Land, M. L., Larimer, F. W., & Hauser, L. J. (2010). Prodigal: prokaryotic gene recognition and translation initiation site identification. BMC bioinformatics, 11(1), 119. Github: https://github.com/hyattpd/Prodigal
- Durrant, M. G., & Bhatt, A. S. (2021). Automated prediction and annotation of small open reading frames in microbial genomes. Cell host & microbe, 29(1), 121-131. Github: https://github.com/bhattlab/SmORFinder
- Stanke, M., Diekhans, M., Baertsch, R., & Haussler, D. (2008). Using native and syntenically mapped cDNA alignments to improve de novo gene finding. Bioinformatics, 24(5), 637-644. Github: https://github.com/Gaius-Augustus/Augustus
- Cantalapiedra, C. P., Hernández-Plaza, A., Letunic, I., Bork, P., & Huerta-Cepas, J. (2021). eggNOG-mapper v2: functional annotation, orthology assignments, and domain prediction at the metagenomic scale. Molecular biology and evolution, 38(12), 5825-5829. Github: https://github.com/eggnogdb/eggnog-mapper
- Huerta-Cepas, J., Szklarczyk, D., Heller, D., Hernández-Plaza, A., Forslund, S. K., Cook, H., ... & Bork, P. (2019). eggNOG 5.0: a hierarchical, functionally and phylogenetically annotated orthology resource based on 5090 organisms and 2502 viruses. Nucleic acids research, 47(D1), D309-D314.
- Buchfink, B., Reuter, K., & Drost, H. G. (2021). Sensitive protein alignments at tree-of-life scale using DIAMOND. Nature methods, 18(4), 366-368.
- Adusumilli, R., & Mallick, P. (2017). Data conversion with ProteoWizard msConvert. In Proteomics: methods and protocols (pp. 339-368). New York, NY: Springer New York. Website: https://proteowizard.sourceforge.io/index.html
- Zhao, M., Su, X. Q., Nian, B., Chen, L. J., Zhang, D. L., Duan, S. M., ... & Ma, Y. (2019). Integrated meta-omics approaches to understand the microbiome of spontaneous fermentation of traditional Chinese pu-erh tea. Msystems, 4(6), 10-1128.
- Monroe, Matthew. (2018, February 21). Fasta File Splitter. [Computer software]. https://doi.org/10.11578/dc.20180319.27. Github: https://github.com/PNNL-Comp-Mass-Spec/Fasta-File-Splitter
- Kim, S., & Pevzner, P. A. (2014). MS-GF+ makes progress towards a universal database search tool for proteomics. Nature communications, 5(1), 5277. Github: https://github.com/MSGFPlus/msgfplus
- Gibbons, Brayson & Monroe, Matthew. Mzid Merger. [Computer software]. Github: https://github.com/PNNL-Comp-Mass-Spec/MzidMerger
- Hinkle, T. B., & Bakalarski, C. E. (2025). Comprehensive Protein Inference Analysis with PyProteinInference Elucidates Biological Understanding of Tandem Mass Spectrometry Data. Journal of proteome research, 24(4), 2135–2140. https://doi.org/10.1021/acs.jproteome.4c00734. Github: https://github.com/thinkle12/pyproteininference?tab=readme-ov-file