Skip to content

Conversation

@Ayushmaan06
Copy link

@Ayushmaan06 Ayushmaan06 commented Mar 14, 2025

Hey @jcharkow !
This PR addresses issue #53 by integrating the feature to plot peptide sequences with matched fragments into the Matplotlib backend interface.
I have followed your instructions from the issue description.
Also followed your instructions on the pr #62 .

Summary by CodeRabbit

  • New Features

    • Introduced a method for peptide sequence annotation in spectrum plots, with customizable display options (font size, colors, highlight) based on user configurations.
    • Enhanced clarity by indicating unsupported plotting modes for peptide sequences in specific backends.
  • Tests

    • Added tests to verify proper peptide sequence rendering on supported backends and ensure clear error handling for unsupported backends.

@coderabbitai
Copy link

coderabbitai bot commented Mar 14, 2025

Walkthrough

The changes introduce peptide sequence plotting functionality into the project. A new method, plot_peptide_sequence, has been added in various plotting classes to handle peptide sequence annotations. In the abstract SpectrumPlot class, the method is declared and conditionally invoked based on configuration settings from an enhanced SpectrumConfig. For the Matplotlib backend, an actual implementation renders text and annotations, while for the Bokeh and Plotly backends, the method raises a NotImplementedError. Additional tests have been added to ensure the correct behavior in both supported and unsupported backends.

Changes

File(s) Change Summary
pyopenms_viz/_bokeh/core.py, pyopenms_viz/_plotly/core.py Add plot_peptide_sequence method that raises a NotImplementedError for unsupported peptide sequence plotting in these backends.
pyopenms_viz/_config.py Augment SpectrumConfig with new fields: display_peptide_sequence, peptide_sequence, matched_fragments to support peptide sequence plotting.
pyopenms_viz/_core.py Introduce an abstract plot_peptide_sequence method in SpectrumPlot and update the plot method to call it conditionally based on configuration settings.
pyopenms_viz/_matplotlib/core.py Implement plot_peptide_sequence to render peptide sequence annotations using Matplotlib for visualizing matched fragments.
test/test_chromatogram.py Add configuration for Matplotlib backend to a non-interactive mode to avoid display issues.
test/test_spectrum.py Add test_spectrum_peptide_sequence_matplotlib to validate plotting of peptide sequences using Matplotlib, including configuration for the Matplotlib backend, and test_spectrum_peptide_sequence_unsupported to check for NotImplementedError in unsupported backends.

Sequence Diagram(s)

sequenceDiagram
    participant S as SpectrumPlot
    participant C as SpectrumConfig
    participant M as MATPLOTLIBSpectrumPlot
    participant U as UnsupportedBackend

    S->>C: Check if display_peptide_sequence is enabled
    alt Enabled (Matplotlib)
        S->>M: Call plot_peptide_sequence(peptide_sequence, matched_fragments)
        M->>M: Render text and annotations via ax.text/annotate
    else Unsupported
        S->>U: Call plot_peptide_sequence
        U-->>S: Raise NotImplementedError
    end
Loading

Possibly related issues

  • Plot peptide sequence with matched fragments. #53: The changes in the main issue are directly related to the modifications proposed in the retrieved issue, as both involve the addition of a plot_peptide_sequence method in the SpectrumPlot class and its integration into the plotting framework, along with updates to the SpectrumConfig class for peptide sequence handling.

Poem

I'm a bunny coding through the night,
Hopping to changes, feeling just right.
Peptide sequences now waltz on the screen,
With Matplotlib magic, a joyful scene.
Bokeh and Plotly say, "Not yet, it seems!"
🐇✨

Tip

⚡🧪 Multi-step agentic review comment chat (experimental)
  • We're introducing multi-step agentic chat in review comments. This experimental feature enhances review discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments.
    - To enable this feature, set early_access to true under in the settings.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
pyopenms_viz/_matplotlib/core.py (1)

586-619: Well-structured implementation of peptide sequence visualization.

Good implementation that:

  1. Places the peptide sequence in the upper left corner with configurable styling
  2. Conditionally handles matched fragments with arrow annotations
  3. Uses configuration properties for consistent visual styling

Consider adding a test case to verify this functionality works as expected with different peptide sequences and matched fragment combinations.

pyopenms_viz/_config.py (1)

365-372: Well-structured implementation of peptide sequence plotting configuration.

The new fields added to the SpectrumConfig class provide a comprehensive set of customization options for peptide sequence plotting. The default values are sensible and follow the established patterns in the codebase.

Consider adding more specific type annotations for matched_fragments. While list[tuple] works, a more precise type like list[tuple[float, float]] (if these tuples represent m/z and intensity values) would improve type safety and code clarity.

-    matched_fragments: list[tuple] = field(default_factory=list)
+    matched_fragments: list[tuple[float, float]] = field(default_factory=list)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40549e8 and abd4036.

📒 Files selected for processing (6)
  • pyopenms_viz/_bokeh/core.py (1 hunks)
  • pyopenms_viz/_config.py (1 hunks)
  • pyopenms_viz/_core.py (2 hunks)
  • pyopenms_viz/_matplotlib/core.py (1 hunks)
  • pyopenms_viz/_plotly/core.py (1 hunks)
  • test/test_chromatogram.py (2 hunks)
🔇 Additional comments (6)
pyopenms_viz/_core.py (2)

692-698: Good abstract method declaration.

The abstract method plot_peptide_sequence follows best practices with clear parameter types, descriptive docstring, and consistent naming.


807-813: Well-implemented conditional peptide sequence plotting.

The conditional logic checks both required config parameters before invoking the method, providing a clean integration with the existing plotting flow.

pyopenms_viz/_plotly/core.py (1)

623-627: Correct implementation of unsupported feature.

The method properly raises a NotImplementedError with a clear message explaining that peptide sequence plotting isn't supported in the Plotly backend.

pyopenms_viz/_bokeh/core.py (1)

548-552: Consistent error handling for unsupported feature.

The NotImplementedError implementation matches the approach used in the Plotly backend, providing a clear message about the lack of support for peptide sequence plotting.

test/test_chromatogram.py (2)

8-11: Good practice using non-interactive Matplotlib backend.

Setting the backend to "Agg" prevents GUI-related issues during testing, which is especially important for CI environments where a display server might not be available.


84-96: Comprehensive testing for unsupported backends.

This parametrized test properly verifies that attempting to use peptide sequence plotting with unsupported backends raises the appropriate exception. The error message matching is also a good practice.

One small inconsistency: This test also uses kind="spectrum" despite being in the test_chromatogram.py file, similar to the issue in the previous test.

Copy link
Collaborator

@jcharkow jcharkow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coming along, thank you for addressing my comments. Althuogh the tests pass there still seems to be some issues. Mainly, it seems that the tests that you added all seem to be skipped. Possibly you forgot to add the snapshots for the new tests? These can be generated with --snapshot-update Also I am unsure why some of the snapshots were updated. Can you please double check (e.g. post screenshots of new and old snapshots) to ensure there are no major changes.

Comment on lines 808 to 811
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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be able to reference directly (e.g. self.display_peptide_sequence, self.peptide_sequence instead of self._config.display_peptide_sequence)

Copy link
Author

@Ayushmaan06 Ayushmaan06 Mar 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done Sir

def test_spectrum_peptide_sequence_matplotlib(chromatogram_data, snapshot):
kwargs = {
"display_peptide_sequence": True,
"peptide_sequence": "PEPTIDEABC",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpicky comment please change "PEPTIDEABC" to "PEPTIDEK" as this is a more standard dummy example in the proteomics community

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done sir

)
fig = out.get_figure()
fig.tight_layout()
assert snapshot == out
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add this snapshot

kind="spectrum",
show_plot=False,
display_peptide_sequence=True,
peptide_sequence="PEPTIDEXYZ",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, change to "PEPTIDEK"

out = chromatogram_data.plot(
x="rt",
y="int",
kind="spectrum",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests should be added to test_spectrum instead of test_chromatogram

@Ayushmaan06 Ayushmaan06 requested a review from jcharkow March 16, 2025 08:21
Copy link
Collaborator

@jcharkow jcharkow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see minor comments below regarding _config. I also edited the tests so now they are not skipped.

While testing on my local machine, I noticed that none of the fragmentation is currently tested/displayed and I am not sure if you implemented this functionality. Please double check #29 what we want is that in the corner of the spectrum we show the peptide sequence as well as its fragmentation pattern (all the lines, in different colors). Note that the ion_annotation and ion_color are specified in the dataframe so we would not need to pass extra arguments.

Please use test/testSpectrumDf.tsv to help with your testing. The sequence is DMAGCH (same as #29 ) and we are expecting y9 to be off just like in that example.

Pleae post an image of the spectrum with this functionality in this PR.

I tried to update the changes to this PR however I do not have the permissions to do so. Please update the tests as per this branch https://github.com/OpenMS/pyopenms_viz/tree/sans/main to ensure that the matplotlib test is not skipped as well.

Comment on lines 61 to 72
@pytest.mark.parametrize("backend", ["ms_bokeh", "ms_plotly"])
def test_chromatogram_peptide_sequence_unsupported(chromatogram_data, backend):
pd.options.plotting.backend = backend
with pytest.raises(NotImplementedError, match="unsupported"):
chromatogram_data.plot(
x="rt",
y="int",
kind="spectrum",
show_plot=False,
display_peptide_sequence=True,
peptide_sequence="PEPTIDEK",
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this test should be in test_spectrum

Comment on lines 614 to 617
arrowprops=dict(arrowstyle="->", color=self._config.highlight_color),
fontsize=self._config.peptide_sequence_fontsize,
color=self._config.highlight_color,
alpha=self._config.highlight_alpha,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be able to use self.highlight_color directly etc

Comment on lines 602 to 603
fontsize=self._config.peptide_sequence_fontsize,
color=self._config.peptide_sequence_color,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be able to use self.peptide_sequence_fontsize directly (remove _config)

Comment on lines 369 to 372
peptide_sequence_fontsize: int = 12
peptide_sequence_color: str = "red"
highlight_color: str = "blue"
highlight_alpha: float = 0.8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see comments below, some of these arguments might not be needed because they are expected to be specified in the dataframe. (lines 365- 372)

@jcharkow jcharkow linked an issue Mar 18, 2025 that may be closed by this pull request
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
pyopenms_viz/_matplotlib/core.py (4)

597-603: Clear docstring with appropriate explanation.

The docstring clearly explains the purpose of the method and how it works. It would be helpful to add parameter descriptions for completeness.

Consider expanding the docstring to include parameter descriptions:

-    """
-    Plot peptide sequence with matched fragments indicated.
-
-    The peptide is displayed in the top corner and the fragmentation pattern
-    is drawn as lines coming out from the letters -- using the dataframe columns
-    'ion_annotation' and 'ion_color' (or 'color_annotation'). No extra arguments are needed.
-    """
+    """
+    Plot peptide sequence with matched fragments indicated.
+
+    The peptide is displayed in the top corner and the fragmentation pattern
+    is drawn as lines coming out from the letters -- using the dataframe columns
+    'ion_annotation' and 'ion_color' (or 'color_annotation'). No extra arguments are needed.
+
+    Parameters
+    ----------
+    peptide_sequence : str
+        The peptide sequence to display
+    matched_fragments : list, optional
+        List of matched fragments as (m/z, intensity) pairs
+    x : float, default=0.5
+        Center horizontal position (axes fraction)
+    y : float, default=0.95
+        Vertical position (axes fraction)
+    spacing : float, default=0.05
+        Spacing between residues (axes fraction)
+    fontsize : int, default=12
+        Font size for peptide sequence
+    fontsize_frag : int, default=10
+        Font size for fragment annotations
+    frag_len : float, default=0.05
+        Length for fragment lines (in axes fraction)
+    """

623-650: Well-handled fragment extraction logic.

The fragment extraction logic is robust, with appropriate fallbacks and error handling. It correctly handles different ion types and positioning.

Consider refactoring the ion type detection into a helper method to improve maintainability.

-                    if ion_type in "abc":
-                        y_offset = frag_len
-                    elif ion_type in "xyz":
-                        y_offset = -frag_len
-                    else:
-                        y_offset = 0
+                    y_offset = self._get_fragment_y_offset(ion_type, frag_len)

And add a helper method:

def _get_fragment_y_offset(self, ion_type, frag_len):
    """
    Determine the y-offset for a fragment based on its ion type.
    
    Parameters
    ----------
    ion_type : str
        The type of ion (a, b, c, x, y, z)
    frag_len : float
        The length of the fragment line
        
    Returns
    -------
    float
        The y-offset for the fragment
    """
    if ion_type in "abc":
        return frag_len
    elif ion_type in "xyz":
        return -frag_len
    else:
        return 0

651-681: Good fragment rendering implementation.

The fragment rendering code handles different fragment formats well and includes appropriate fallbacks for non-string colors. The visualization logic with lines and text is implemented properly.

Based on previous review comments, you might want to use class attributes if they're available:

-                color=frag_color,
+                color=frag_color if not hasattr(self, "highlight_color") else self.highlight_color,

And:

-                fontsize=fontsize_frag,
+                fontsize=fontsize_frag if not hasattr(self, "peptide_sequence_fontsize") else self.peptide_sequence_fontsize,

586-681: Consider adding type annotations for improved code readability.

The method would benefit from complete type annotations, especially for the matched_fragments parameter.

-    def plot_peptide_sequence(
-        self,
-        peptide_sequence: str,
-        matched_fragments=None,
-        x: float = 0.5,          # center horizontal position (axes fraction)
-        y: float = 0.95,         # vertical position (axes fraction)
-        spacing: float = 0.05,   # spacing between residues (axes fraction)
-        fontsize: int = 12,
-        fontsize_frag: int = 10,
-        frag_len: float = 0.05   # length for fragment lines (in axes fraction)
-    ):
+    def plot_peptide_sequence(
+        self,
+        peptide_sequence: str,
+        matched_fragments: list[tuple] | None = None,
+        x: float = 0.5,          # center horizontal position (axes fraction)
+        y: float = 0.95,         # vertical position (axes fraction)
+        spacing: float = 0.05,   # spacing between residues (axes fraction)
+        fontsize: int = 12,
+        fontsize_frag: int = 10,
+        frag_len: float = 0.05   # length for fragment lines (in axes fraction)
+    ) -> None:
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 290aecf and 59a840d.

⛔ Files ignored due to path filters (1)
  • test/__snapshots__/test_spectrum/test_spectrum_peptide_sequence_matplotlib[ms_matplotlib].png is excluded by !**/*.png
📒 Files selected for processing (4)
  • pyopenms_viz/_config.py (1 hunks)
  • pyopenms_viz/_matplotlib/core.py (1 hunks)
  • test/test_chromatogram.py (2 hunks)
  • test/test_spectrum.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/test_chromatogram.py
  • pyopenms_viz/_config.py
🧰 Additional context used
🧬 Code Definitions (2)
test/test_spectrum.py (3)
test/conftest.py (2) (2)
  • spectrum_data (76-77)
  • snapshot (41-50)
pyopenms_viz/_matplotlib/core.py (4) (4)
  • plot (294-316)
  • plot (325-385)
  • plot (405-469)
  • plot (701-718)
pyopenms_viz/_matplotlib/__init__.py (1) (1)
  • plot (33-41)
pyopenms_viz/_matplotlib/core.py (1)
pyopenms_viz/_core.py (6) (6)
  • plot_peptide_sequence (693-698)
  • plot (343-347)
  • plot (580-602)
  • plot (647-649)
  • plot (757-862)
  • plot (1185-1197)
🔇 Additional comments (5)
test/test_spectrum.py (3)

9-11: Good setup for matplotlib in tests.

The explicit setting of the Matplotlib backend to "Agg" ensures tests will run in headless environments, which is perfect for CI/CD pipelines.


99-118: Well-structured test for peptide sequence visualization.

This test appropriately verifies that the Matplotlib backend correctly handles peptide sequence plotting with matched fragments. The test provides good coverage of the new functionality.

A few observations:

  • The docstring clearly explains the test's purpose
  • The test uses appropriate test data with dummy peptide sequence and matched fragments
  • The snapshot testing approach ensures visual consistency

120-131: Good test for unsupported backends.

This test correctly verifies that attempting to use peptide sequence plotting with unsupported backends raises the appropriate exception. The parametrization ensures both Bokeh and Plotly backends are tested.

pyopenms_viz/_matplotlib/core.py (2)

586-596: Well-defined method signature with good defaults.

The method signature is clear with descriptive parameter names and appropriate default values. The comments on each parameter help readers understand what each parameter does without needing to read the docstring.


606-621: Good centering logic and amino acid rendering.

The centering calculation is elegant and ensures the peptide sequence is properly positioned. The rendering of individual amino acids is implemented correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Plot peptide sequence with matched fragments.

2 participants