-
Notifications
You must be signed in to change notification settings - Fork 17
AlphaPept Protein Group Reader #327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
86 commits
Select commit
Hold shift + click to select a range
700b156
[Feature] Add alphapept protein group matrix reader
lucas-diedrich 0d1e91e
[Doc] Add explanatory comments for magic values
lucas-diedrich cfc69d3
[Feature] Add configuration of alphapept protein group reader
lucas-diedrich 79087aa
[Feature] Add keys for alphapept reader
lucas-diedrich 754453e
[Fix] Bug fix. Keep dataframe index if no features are specified and …
lucas-diedrich 38d4c7d
[Doc] Add explanatory comment
lucas-diedrich 7e2a310
[Fix] Fix type hint
lucas-diedrich 7ab7adf
[Tests] Unittests for the index parsing function of the alphapept reader
lucas-diedrich 6f71280
[Fix] Bug fixes for the parsing of alphapept indices
lucas-diedrich abaacd7
[Doc] Fix examples
lucas-diedrich 3ae462e
[API] Expose alphapept reader
lucas-diedrich 034047c
[Tests] Add integration tests for alphapet
lucas-diedrich 80de4c9
[Doc] Add examples
lucas-diedrich 6d9cc76
[Tests] Use public AlphaPeptPGReader instead of module level import
lucas-diedrich 5b70307
[Typing] Add type hints to tests
lucas-diedrich 65445cb
[Doc] Fix incorrect reader name
lucas-diedrich 4d8cc57
[Doc] Fix typo
lucas-diedrich bb300b1
[Doc] Update docstring
lucas-diedrich 19d0ca4
[Fix] Incorporate suggestions from Copilot review
lucas-diedrich 6c59695
[Doc] Fix typos in docstrings
lucas-diedrich be74704
[Refactor] Refactor so that the method does not depend on custom load…
lucas-diedrich 0c01e84
[Test] Add tests for alphapept hdf files
lucas-diedrich 000b094
[Feature] Implement pre-configured regular expressions
lucas-diedrich b67b3f6
[Refactor] Restructure pg_reader_yaml to accomodate pre-configured re…
lucas-diedrich 5c895b4
[Doc] Expose pre-configured keys in class init as type hints. Improve…
lucas-diedrich 5031247
[Test] Add tests for _get_measurement_regex
lucas-diedrich a738164
[Test] Adjust test based on new config structure
lucas-diedrich a6533c1
[Tests] Remove unnecessary tests of reader_provider import
lucas-diedrich 9be20bb
[Doc] Fix docstring
lucas-diedrich 39ab064
[Requirements] Add pytables dependency which is necessary to read hdf…
lucas-diedrich f083adb
[Tests] Add exact comparison for integration test
lucas-diedrich ec85043
[Doc] Clean up comments in config file
lucas-diedrich 182a74d
[Config] Add column mapping explicitly to make explicity which index …
lucas-diedrich d4d16ea
[Doc] Cleaned up docstring
lucas-diedrich 48c227a
[Fix] Fix missing import
lucas-diedrich 6162c0a
[Fix] Refactor conftests - skip gracefully if connection times out, a…
lucas-diedrich 60a835e
[Test] Make conftests only depend on local data if possible.
lucas-diedrich f63a0e3
[Test] Adjust expected shapes for alphapeptreader based on new testd …
lucas-diedrich 0422980
[Tests] Add test data
lucas-diedrich 6fe8305
[Refactor] Move all constants to class constants
lucas-diedrich 27c1e37
[Nit] Warn if unexpected format is encountered
lucas-diedrich 798ac79
[Fix] Remove unnecessary helper function
lucas-diedrich 3891bcd
[Feature] Configuration for MaxQuant reader
lucas-diedrich 255c978
[Feature] Add post-processing method that acts on streamlined columns…
lucas-diedrich 7c1de7d
[API] Expose MaxQuantPGReader to users
lucas-diedrich 843108a
[Feature] MaxQuant reader with documentation
lucas-diedrich 551f963
[Test] Add integration test for MaxQuantPGReader
lucas-diedrich fe922c5
[Test] Adjust tests to work with local test data - MQReader
lucas-diedrich 3b79dce
[Tests] Add test data
lucas-diedrich 9f4d3e7
[Fix] Fix typo
lucas-diedrich 521fa13
[Doc] Update docstring, add more explicit parameter explanations
lucas-diedrich 3fd9d98
[Doc] Update docstrings and remove incorrect copy documentation
lucas-diedrich 7717cd2
[Doc] Clarify docstring
lucas-diedrich 31e46e3
[Feature] Spectronaut reader
lucas-diedrich 5aaf207
[Feature] Spectronaut reader config
lucas-diedrich 3cfc4ca
[API] Expose spectronaut reader to users
lucas-diedrich f28d73e
[Test] Spectronaut integration tests
lucas-diedrich 4573149
[Doc] Add examples
lucas-diedrich c287cd2
[Fix] Rename pre-configured regex to default
lucas-diedrich 4940a73
[Fix] Fix typos
lucas-diedrich b5c7a9b
[Feature] Add parquet support. Specifically desirable for spectronaut…
lucas-diedrich 41eef70
[Test] Add integration test for spectronaut.parquet report
lucas-diedrich 207e386
[Doc] Add regular expression documentation
lucas-diedrich ef71f1a
[Doc] Improve docstring of class initialization
lucas-diedrich a2427d7
[Feature] Add additional column mapping for parquet report protein gr…
lucas-diedrich 0e13e68
[Test] Refactor tests so that they work with local data
lucas-diedrich 5e9c1c0
[Test-Data] Add test data reference for spectronaut reports
lucas-diedrich 85e05cb
[Feature] Implement fragpipe reader
lucas-diedrich 4a46205
[API] Expose FragPipeReader to users
lucas-diedrich 808547b
[Tests] Add integration test for FragPipeReader
lucas-diedrich 38b995d
[Fix] Fix typo in URL
lucas-diedrich deccde6
[Test] Update tests to work with local data (FragPipe PG reader)
lucas-diedrich 6cbe7d9
[Test-data] Add test reference data (PG fragpipe)
lucas-diedrich cc9b861
[Feature] Add MZTab protein group reader
lucas-diedrich 6699fac
[API] Expose MZTab to users
lucas-diedrich 8e0e8c5
[Tests] Add integration tests
lucas-diedrich 2a2848e
[Refactor] Set correct default values
lucas-diedrich 00c72f0
[Tests] Add integration tests
lucas-diedrich 86eeb7a
[Test] Refactor mztab integration test so that it runs with local data
lucas-diedrich 15545aa
[Test-data] Add local test data (mzTAB PG Reader)
lucas-diedrich 0343aeb
[Doc] Add PG-reader API docs
lucas-diedrich 75b5ab1
Merge pull request #334 from MannLabs/pg-reader-9-docs-I
lucas-diedrich 639c81e
Merge pull request #333 from MannLabs/pg-reader-8-mztab
lucas-diedrich 778dac6
Merge pull request #332 from MannLabs/pg-reader-7-msfragger
lucas-diedrich e9485c1
Merge pull request #331 from MannLabs/pg-reader-6-spectronaut
lucas-diedrich 0be157e
Merge pull request #330 from MannLabs/pg-reader-5-maxquant
lucas-diedrich File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,19 @@ | ||
| from .alphadia_pg_reader import AlphaDiaPGReader | ||
| from .alphapept_pg_reader import AlphaPeptPGReader | ||
| from .diann_pg_reader import DiannPGReader | ||
| from .fragpipe_pg_reader import FragPipePGReader | ||
| from .maxquant_pg_reader import MaxQuantPGReader | ||
| from .mztab_pg_reader import MZTabPGReader | ||
| from .pg_reader import pg_reader_provider | ||
| from .spectronaut_reader import SpectronautPGReader | ||
|
|
||
| __all__ = ["pg_reader_provider", "AlphaDiaPGReader", "DiannPGReader"] | ||
| __all__ = [ | ||
| "pg_reader_provider", | ||
| "AlphaDiaPGReader", | ||
| "DiannPGReader", | ||
| "AlphaPeptPGReader", | ||
| "MaxQuantPGReader", | ||
| "SpectronautPGReader", | ||
| "FragPipePGReader", | ||
| "MZTabPGReader", | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,289 @@ | ||
| """AlphaPept protein group reader.""" | ||
|
|
||
| import re | ||
| import warnings | ||
| from typing import Any, Literal, Optional, Union | ||
|
|
||
| import pandas as pd | ||
|
|
||
| from .keys import PGCols | ||
| from .pg_reader import PGReaderBase, pg_reader_provider | ||
|
|
||
|
|
||
| class AlphaPeptPGReader(PGReaderBase): | ||
| """Reader for protein group matrices from the alphapept search engine. | ||
|
|
||
| Per default, the reader will read raw intensities from the protein group matrix. By passing a | ||
| suitable regular expression, it is also possible to extract LFQ corrected intensities from the | ||
| reader. | ||
|
|
||
| Notes: | ||
| ----- | ||
| AlphaPept protein group matrices contain both raw intensities and LFQ-corrected intensities. | ||
| The LFQ-corrected intensities are marked by an `_LFQ` suffix. | ||
|
|
||
| Example: | ||
| ------- | ||
| Get example data | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| import os | ||
| import tempfile | ||
| from alphabase.tools.data_downloader import DataShareDownloader | ||
| from alphabase.pg_reader import AlphaPeptPGReader | ||
|
|
||
|
|
||
| # Download to temporary directory | ||
| URL = "https://datashare.biochem.mpg.de/s/6G6KHJqwcRPQiOO" | ||
| download_dir = tempfile.mkdtemp() | ||
|
|
||
| download_path = DataShareDownloader(url=URL, output_dir=download_dir).download() | ||
|
|
||
|
|
||
| Per default, the reader will return the raw intensities. Additional protein features are stored | ||
| in the dataframe index, samples are stored as columns. | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| # Get raw intensities | ||
| reader = AlphaPeptPGReader() | ||
| results = reader.import_file(download_path) | ||
| results.index.names | ||
| > FrozenList(['proteins', 'uniprot_ids', 'ensembl_ids', 'source_db', 'is_decoy']) | ||
| results.columns | ||
| > Index(['A', 'B'], dtype='object') | ||
|
|
||
| To read the LFQ values, pass the pre-configured key `lfq` to the reader, which represents a regular expression | ||
| that automatically extracts the `LFQ` columns from the protein group table. | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| # Get raw intensities | ||
| reader = AlphaPeptPGReader(measurement_regex="lfq") | ||
| results = reader.import_file(download_path) | ||
| results.index.names | ||
| > FrozenList(['proteins', 'uniprot_ids', 'ensembl_ids', 'source_db', 'is_decoy']) | ||
| results.columns | ||
| > Index(['A_LFQ', 'B_LFQ'], dtype='object') | ||
|
lucas-diedrich marked this conversation as resolved.
|
||
|
|
||
|
|
||
| To check out all preconfigured regular expressions, use the `get_preconfigured_regex` method: | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| AlphaPeptPGReader.get_preconfigured_regex() | ||
| > {'raw': '^.*(?<!_LFQ)$', 'lfq': '_LFQ$'} | ||
|
|
||
| """ | ||
|
|
||
| _reader_type: str = "alphapept" | ||
|
|
||
| # Report file settings (delimiter + index column) | ||
| _FILE_DELIMITER: str = "," | ||
| # alphapept does not set a name for the feature column, i.e. it is set to the pandas default | ||
| _INDEX_COL: str = "Unnamed: 0" | ||
|
|
||
| # Default delimiter in fasta file headers | ||
| _ENTRY_DELIMITER: str = "|" | ||
|
|
||
| # Feature settings | ||
| # Decoys are prefixed with REV__ in alphapept | ||
| _DECOY_REGEX: str = "^REV__" | ||
|
lucas-diedrich marked this conversation as resolved.
|
||
| # Ensembl IDs are identified with a ENSEMBL prefix | ||
| _ENSEMBL_REGEX: str = "^ENSEMBL:" | ||
| _ENSEMBL_NAME: str = "ENSEMBL" | ||
|
|
||
| # The expected length of fasta headers is 3 (sp|Uniprot ID|Uniprot Name) | ||
| _FASTA_HEADER_DEFAULT_LENGTH: int = 3 | ||
| _NA_STR: str = "na" | ||
| _PG_DELIMITER: str = ";" | ||
|
|
||
| def __init__( | ||
| self, | ||
| *, | ||
| column_mapping: Optional[dict[str, Any]] = None, | ||
| measurement_regex: Union[str, Literal["raw", "lfq"], None] = "raw", # noqa: PYI051 raw and lfq are special cases and not equivalent to string | ||
| ): | ||
| """Initialize AlphaPept protein group matrix reader. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| column_mapping | ||
| Dictionary mapping alphabase column names (keys) to AlphaPept column names (values). | ||
| If `None`, uses default mapping from configuration file. | ||
| measurement_regex | ||
| Pattern to select quantity columns | ||
|
|
||
| - "raw" (default): Raw intensities (excludes _LFQ columns) | ||
| - "lfq": LFQ-corrected intensities (_LFQ suffix) | ||
| - str: Custom regular expression pattern | ||
| - None: All quantity columns | ||
|
|
||
| See class documentation for usage examples and `get_preconfigured_regex()` for available patterns. | ||
|
|
||
| """ | ||
| super().__init__( | ||
| column_mapping=column_mapping, measurement_regex=measurement_regex | ||
| ) | ||
|
|
||
| def _pre_process(self, df: pd.DataFrame) -> pd.DataFrame: | ||
| """Preprocess of alphapept protein group report and return modified copy of the dataframe. | ||
|
|
||
| Processes feature index to a parsed, streamlined version. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| df | ||
| alphapept protein group report. | ||
|
|
||
| Returns | ||
| ------- | ||
| :class:`pd.DataFrame` | ||
| Modified copy of protein group report with parsed index. The index contains the levels | ||
| - proteins: str | ||
| - uniprot_ids: str | ||
| - ensembl_ids: str | ||
| - source_db: str | ||
| - is_decoy: bool | ||
|
|
||
| """ | ||
| df = df.copy() | ||
|
|
||
| # alphapept does not set a name for the feature column | ||
| # load it as regular column and set it to index afterwards | ||
| df = df.set_index(self._INDEX_COL) | ||
|
|
||
| # Parse index | ||
| parsed_index: list[dict[str, str]] = list( | ||
| df.index.map(lambda idx: self._parse_alphapept_index(idx)) | ||
| ) | ||
|
|
||
| # Overwrite index with streamlined version | ||
| df.index = pd.MultiIndex.from_frame(pd.DataFrame(parsed_index)) | ||
|
|
||
| return df | ||
|
|
||
| def _parse_alphapept_index(self, identifier: str) -> dict[str, str]: | ||
| """Parse protein identifier from AlphaPept protein group table. | ||
|
|
||
| Parameters | ||
| ---------- | ||
| identifier : str | ||
| Protein identifier string from AlphaPept | ||
|
|
||
| Returns | ||
| ------- | ||
| dict | ||
| Dictionary with parsed components: | ||
| - proteins: str, semicolon-separated protein names or self._NA_STR | ||
| - uniprot_ids: str, semicolon-separated UniProt IDs or self._NA_STR | ||
| - ensembl_ids: str, semicolon-separated ENSEMBL IDs or self._NA_STR | ||
| - source_db: str, semicolon-separated data sources or self._NA_STR | ||
| - is_decoy: bool, True if any identifier in a protein group starts with "REV__" | ||
|
|
||
| Examples | ||
| -------- | ||
|
|
||
| .. code-block:: python | ||
|
|
||
| # sp|Q9NQT4|EXOS5_HUMAN | ||
| {"source_db": "sp", "uniprot_ids": "Q9NQT4", "ensembl_ids": "na", "proteins": "EXOS5_HUMAN", "is_decoy": False} | ||
|
|
||
| # Q0IIK2 | ||
| {"source_db": self._NA_STR, "uniprot_ids": "Q0IIK2", "ensembl_ids": "na", "proteins": self._NA_STR, "is_decoy": False} | ||
|
|
||
| # "sp|Q9H2K8|TAOK3_HUMAN,sp|Q7L7X3|TAOK1_HUMAN" | ||
| {"source_db": "sp;sp", "uniprot_ids": "Q9H2K8;Q7L7X3", "ensembl_ids": "na;na", "proteins": "TAOK3_HUMAN;TAOK1_HUMAN", "is_decoy": False} | ||
|
|
||
| # ENSEMBL:ENSBTAP00000024146 | ||
| {"source_db": "ENSEMBL", "uniprot_ids": self._NA_STR, "ensembl_ids": "ENSBTAP00000024146", "proteins": self._NA_STR, "is_decoy": False} | ||
|
|
||
| # ENSEMBL:ENSBTAP00000024146,sp|P35520|CBS_HUMAN | ||
| {"source_db": "ENSEMBL;sp", "uniprot_ids": "P35520", "ensembl_ids": "ENSBTAP00000024146", "proteins": "CBS_HUMAN", "is_decoy": False} | ||
|
|
||
| # REV__sp|Q13085|ACACA_HUMAN | ||
| {"source_db": "REV__sp", "uniprot_ids": "Q13085", "ensembl_ids": "na", "proteins": "ACACA_HUMAN", "is_decoy": True} | ||
|
|
||
| """ | ||
| decoy_pattern = re.compile(self._DECOY_REGEX) | ||
| ensembl_pattern = re.compile(self._ENSEMBL_REGEX) | ||
|
|
||
| # Multiple proteins are separted by comma | ||
| protein_entries = identifier.split(",") | ||
|
lucas-diedrich marked this conversation as resolved.
|
||
|
|
||
| source_db: list[str] = [] | ||
| uniprot_ids: list[str] = [] | ||
| ensembl_ids: list[str] = [] | ||
| proteins: list[str] = [] | ||
| is_decoy: list[bool] = [] | ||
|
|
||
| for entry in protein_entries: | ||
| # Decoys | ||
| # Identify decoys and remove decoy prefix if present | ||
| entry_is_decoy = bool(decoy_pattern.search(entry)) | ||
| is_decoy.append(entry_is_decoy) | ||
|
|
||
| # Check for ENSEMBL format (ENSEMBL:IDENTIFIER) | ||
| if re.search(ensembl_pattern, entry): | ||
| source_db.append(self._ENSEMBL_NAME) | ||
|
|
||
| # Remove "ENSEMBL:" prefix | ||
| uniprot_ids.append(self._NA_STR) | ||
| proteins.append(self._NA_STR) | ||
| ensembl_ids.append(re.sub(ensembl_pattern, "", entry)) | ||
|
|
||
| # Check if entry contains pipe separators (UniProt format) | ||
| # Options: | ||
| # sp|Q9H2K8|TAOK3_HUMAN | ||
| # Q9H2K8 | ||
|
|
||
| # TODO: How to handle REV sequences here? | ||
| # Currently they are only marked by the DECOY_INDICATOR flag, but should the individual identifiers be flagged as well? | ||
|
lucas-diedrich marked this conversation as resolved.
|
||
| elif self._ENTRY_DELIMITER in entry: | ||
| parts = entry.split(self._ENTRY_DELIMITER) | ||
| if len(parts) == self._FASTA_HEADER_DEFAULT_LENGTH: | ||
| source_db.append(parts[0]) | ||
| uniprot_ids.append(parts[1]) | ||
| proteins.append(parts[2]) | ||
| ensembl_ids.append(self._NA_STR) | ||
| else: | ||
| # Handle unexpected format | ||
|
lucas-diedrich marked this conversation as resolved.
|
||
| warnings.warn( | ||
| f"Encountered unexpected format. Set {entry} to proteins.", | ||
| stacklevel=2, | ||
| ) | ||
| source_db.append(self._NA_STR) | ||
| uniprot_ids.append(self._NA_STR) | ||
| proteins.append(entry) | ||
| ensembl_ids.append(self._NA_STR) | ||
| else: | ||
| # No pipes or ENSEMBL prefix, assume it's just a UniProt ID | ||
| uniprot_ids.append(entry) | ||
| source_db.append(self._NA_STR) | ||
| proteins.append(self._NA_STR) | ||
| ensembl_ids.append(self._NA_STR) | ||
|
|
||
| # Join with semicolons or use self._NA_STR if empty | ||
| source_db_str = ( | ||
| self._PG_DELIMITER.join(source_db) if source_db else self._NA_STR | ||
| ) | ||
| uniprot_ids_str = ( | ||
| self._PG_DELIMITER.join(uniprot_ids) if uniprot_ids else self._NA_STR | ||
| ) | ||
| ensembl_ids_str = ( | ||
| self._PG_DELIMITER.join(ensembl_ids) if ensembl_ids else self._NA_STR | ||
| ) | ||
| proteins_str = self._PG_DELIMITER.join(proteins) if proteins else self._NA_STR | ||
| is_decoy = any(is_decoy) | ||
|
|
||
| return { | ||
| PGCols.PROTEINS: proteins_str, | ||
| PGCols.UNIPROT_IDS: uniprot_ids_str, | ||
| PGCols.ENSEMBL_IDS: ensembl_ids_str, | ||
| PGCols.SOURCE_DB: source_db_str, | ||
| PGCols.DECOY_INDICATOR: is_decoy, | ||
| } | ||
|
|
||
|
|
||
| pg_reader_provider.register_reader("alphapept", reader_class=AlphaPeptPGReader) | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.