From abd40364ef78ba166c0fe39dc284c09971369ed4 Mon Sep 17 00:00:00 2001 From: ayushmaan Date: Fri, 14 Mar 2025 17:14:50 +0530 Subject: [PATCH 1/6] Peptide Sequence Plotting --- pyopenms_viz/_bokeh/core.py | 6 ++- pyopenms_viz/_config.py | 9 ++++ pyopenms_viz/_core.py | 15 +++++++ pyopenms_viz/_matplotlib/core.py | 34 ++++++++++++++- pyopenms_viz/_plotly/core.py | 6 +++ .../test_peakmap_marginals[ms_bokeh].html | 10 ++--- .../test_peakmap_mz_im[ms_bokeh].html | 10 ++--- test/test_chromatogram.py | 41 +++++++++++++++++++ 8 files changed, 119 insertions(+), 12 deletions(-) diff --git a/pyopenms_viz/_bokeh/core.py b/pyopenms_viz/_bokeh/core.py index 0450d71f..958ee05a 100644 --- a/pyopenms_viz/_bokeh/core.py +++ b/pyopenms_viz/_bokeh/core.py @@ -545,7 +545,11 @@ class BOKEHSpectrumPlot(BOKEH_MSPlot, SpectrumPlot): Class for assembling a Bokeh spectrum plot """ - pass + def plot_peptide_sequence(self, peptide_sequence: str, matched_fragments=None): + """ + Raises a NotImplementedError because peptide sequence plotting is not supported for Bokeh. + """ + raise NotImplementedError("Peptide sequence plotting is currently unsupported in the Bokeh backend.") class BOKEHPeakMapPlot(BOKEH_MSPlot, PeakMapPlot): diff --git a/pyopenms_viz/_config.py b/pyopenms_viz/_config.py index 0b79487c..d3069686 100644 --- a/pyopenms_viz/_config.py +++ b/pyopenms_viz/_config.py @@ -362,6 +362,15 @@ class SpectrumConfig(VLineConfig): mirror_spectrum: bool = False peak_color: str | None = None + # New fields for peptide sequence plotting + display_peptide_sequence: bool = False + peptide_sequence: str = "" + matched_fragments: list[tuple] = field(default_factory=list) + peptide_sequence_fontsize: int = 12 + peptide_sequence_color: str = "red" + highlight_color: str = "blue" + highlight_alpha: float = 0.8 + # Binning settings bin_peaks: Union[Literal["auto"], bool] = False bin_method: Literal["none", "sturges", "freedman-diaconis", "mz-tol-bin"] = ( diff --git a/pyopenms_viz/_core.py b/pyopenms_viz/_core.py index 62d51c02..02b85673 100644 --- a/pyopenms_viz/_core.py +++ b/pyopenms_viz/_core.py @@ -688,6 +688,14 @@ def __init__( super().__init__(data, **kwargs) self.plot() + + @abstractmethod + def plot_peptide_sequence(self, peptide_sequence: str, matched_fragments=None): + """ + Renders a peptide sequence annotation on the spectrum. + Must be implemented by each backend (e.g., matplotlib). + """ + pass def load_config(self, **kwargs): if self._config is None: @@ -796,6 +804,13 @@ def plot(self): self.canvas, ann_texts, ann_xs, ann_ys, ann_colors ) + # If config says display_sequence, call the abstract method + if self._config.display_peptide_sequence and self._config.peptide_sequence: + self.plot_peptide_sequence( + self._config.peptide_sequence, + matched_fragments=self._config.matched_fragments + ) + # Mirror spectrum if self.mirror_spectrum and self.reference_spectrum is not None: ## create a mirror spectrum diff --git a/pyopenms_viz/_matplotlib/core.py b/pyopenms_viz/_matplotlib/core.py index 11e7c737..c041463e 100644 --- a/pyopenms_viz/_matplotlib/core.py +++ b/pyopenms_viz/_matplotlib/core.py @@ -583,7 +583,39 @@ class MATPLOTLIBSpectrumPlot(MATPLOTLIB_MSPlot, SpectrumPlot): Class for assembling a matplotlib spectrum plot """ - pass + def plot_peptide_sequence(self, peptide_sequence: str, matched_fragments=None): + """ + Renders a peptide sequence annotation on the spectrum using matplotlib. + + Args: + peptide_sequence (str): The peptide sequence to display. + matched_fragments (list, optional): List of (fragment_index, intensity) tuples or similar. + """ + ax = self.ax + + # Example: place the peptide sequence in the upper left corner + ax.text( + 0.02, + 0.95, + f"Peptide: {peptide_sequence}", + transform=ax.transAxes, + fontsize=self._config.peptide_sequence_fontsize, + color=self._config.peptide_sequence_color, + verticalalignment="top", + ) + + # If matched_fragments passed in, annotate them as an example: + if matched_fragments: + for (frag_index, frag_intensity) in matched_fragments: + ax.annotate( + f"Frag {frag_index}", + xy=(frag_index, frag_intensity), + xytext=(frag_index, frag_intensity + 0.02), + arrowprops=dict(arrowstyle="->", color=self._config.highlight_color), + fontsize=self._config.peptide_sequence_fontsize, + color=self._config.highlight_color, + alpha=self._config.highlight_alpha, + ) class MATPLOTLIBPeakMapPlot(MATPLOTLIB_MSPlot, PeakMapPlot): diff --git a/pyopenms_viz/_plotly/core.py b/pyopenms_viz/_plotly/core.py index b106a044..0c3618b0 100644 --- a/pyopenms_viz/_plotly/core.py +++ b/pyopenms_viz/_plotly/core.py @@ -619,6 +619,12 @@ def _prepare_data(self, df, label_suffix=" (ref)"): self.reference_spectrum[self.by] + label_suffix ) return df + + def plot_peptide_sequence(self, peptide_sequence: str, matched_fragments=None): + """ + Raises a NotImplementedError because peptide sequence plotting is not supported for Plotly. + """ + raise NotImplementedError("Peptide sequence plotting is currently unsupported in the Plotly backend.") class PLOTLYPeakMapPlot(PLOTLY_MSPlot, PeakMapPlot): diff --git a/test/__snapshots__/test_peakmap_marginals/test_peakmap_marginals[ms_bokeh].html b/test/__snapshots__/test_peakmap_marginals/test_peakmap_marginals[ms_bokeh].html index 112f1fa6..1b447d64 100644 --- a/test/__snapshots__/test_peakmap_marginals/test_peakmap_marginals[ms_bokeh].html +++ b/test/__snapshots__/test_peakmap_marginals/test_peakmap_marginals[ms_bokeh].html @@ -18,10 +18,10 @@ -
+
- -
+
- -
+
- -
+
-