Skip to content

feat: add .ms_plot accessor to Pandas DataFrames for API parity#165

Closed
Sanjith1013 wants to merge 5 commits into
OpenMS:mainfrom
Sanjith1013:feat-pandas-ms-plot
Closed

feat: add .ms_plot accessor to Pandas DataFrames for API parity#165
Sanjith1013 wants to merge 5 commits into
OpenMS:mainfrom
Sanjith1013:feat-pandas-ms-plot

Conversation

@Sanjith1013

@Sanjith1013 Sanjith1013 commented Mar 13, 2026

Copy link
Copy Markdown
Contributor

Description

Following up on the discussion in PR #164 regarding API unification, this PR introduces the .ms_plot namespace directly to Pandas DataFrames.

By using @pd.api.extensions.register_dataframe_accessor, users can now use the exact same syntax (df.ms_plot()) regardless of whether they are working with Pandas or Polars.

Technical Details:

  • Created _pandas_accessor.py to securely delegate .ms_plot() calls to the native pandas.DataFrame.plot() backend.
  • This ensures that all existing configurations, like pd.options.plotting.backend = "ms_plotly", are perfectly respected without duplicating any rendering logic.
  • Registered the namespace in __init__.py for seamless import side-effects.

Testing

  • Added test_pandas_accessor.py using the syrupy snapshot framework to mathematically guarantee that the Plotly JSON output matches the expected structure.
  • Scoped the load_backend fixture to prevent global state leaks in conftest.py.

cc: @singjc - Thanks for the great suggestion to unify the API!

Summary by CodeRabbit

  • New Features

    • Added an ms_plot accessor for pandas DataFrames to plot mass spectra directly; it registers automatically on import.
  • Tests

    • Added snapshot-backed tests (Plotly, Bokeh, Matplotlib variants) to ensure consistent mass spectrum rendering and deterministic output across backends.

Copilot AI review requested due to automatic review settings March 13, 2026 09:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a Pandas DataFrame accessor to expose the project’s plotting API under df.ms_plot(...), aiming to align the call site with the existing “namespace” style used elsewhere and keep delegation routed through Pandas’ plotting backend mechanism.

Changes:

  • Registered a new Pandas DataFrame accessor (ms_plot) that delegates to DataFrame.plot(...).
  • Imported the accessor module from pyopenms_viz.__init__ to enable registration via import side effects.
  • Added a syrupy snapshot test (and snapshot artifact) for the new accessor.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
pyopenms_viz/_pandas_accessor.py Introduces the ms_plot DataFrame accessor that forwards calls to DataFrame.plot.
pyopenms_viz/__init__.py Imports the accessor module for registration side effects when pyopenms_viz is imported.
test/test_pandas_accessor.py Adds a snapshot test covering df.ms_plot(kind="spectrum", ...).
test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot.json Stores expected Plotly JSON output for the new accessor test.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pyopenms_viz/__init__.py Outdated
import types
from pathlib import Path
from ._core import plot_chromatogram, plot_spectrum, plot_mobilogram, plot_peakmap
from . import _pandas_accessor # Import for side effects: registers Pandas 'ms_plot' namespace. noqa: F401
Comment thread test/test_pandas_accessor.py Outdated
Comment on lines +37 to +40
backend="ms_plotly",
show_plot=False
)

Comment thread test/test_pandas_accessor.py Outdated
Comment on lines +5 to +17
@pytest.fixture(autouse=True)
def load_backend():
"""
Safely override the global backend so the syrupy snapshot fixture
in conftest.py knows which extension to load, then reset it.
"""
original_backend = pd.options.plotting.backend
pd.options.plotting.backend = "ms_plotly"

yield

# Teardown: restore the original state
pd.options.plotting.backend = original_backend
Comment thread test/test_pandas_accessor.py Outdated
Comment on lines +5 to +10
@pytest.fixture(autouse=True)
def load_backend():
"""
Safely override the global backend so the syrupy snapshot fixture
in conftest.py knows which extension to load, then reset it.
"""
@coderabbitai

coderabbitai Bot commented Mar 13, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8b5862e5-5843-44d6-9eae-ea5cf40aad4f

📥 Commits

Reviewing files that changed from the base of the PR and between e321f28 and c0be234.

📒 Files selected for processing (3)
  • pyopenms_viz/__init__.py
  • test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot[ms_plotly].json
  • test/test_pandas_accessor.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/test_pandas_accessor.py
  • test/snapshots/test_pandas_accessor/test_pandas_ms_plot_snapshot[ms_plotly].json

📝 Walkthrough

Walkthrough

Registers a new Pandas DataFrame accessor ms_plot in pyopenms_viz that delegates plotting calls to the DataFrame.plot machinery; adds tests and snapshot fixtures validating output across Matplotlib, Plotly, and Bokeh backends.

Changes

Cohort / File(s) Summary
Package init & accessor
pyopenms_viz/__init__.py, pyopenms_viz/_pandas_accessor.py
Adds import of _pandas_accessor for side-effect registration and implements PandasPlotAccessor registered as ms_plot, with __init__ and __call__ delegating to DataFrame.plot.
Tests & snapshots
test/test_pandas_accessor.py, test/__snapshots__/test_pandas_accessor/*, test/__snapshots__/*test_pandas_ms_plot_snapshot[ms_bokeh].html, test/__snapshots__/*test_pandas_ms_plot_snapshot[ms_plotly].json
Adds unit test exercising df.ms_plot() and multiple snapshot artifacts (Plotly JSON, Bokeh HTML, Matplotlib snapshot) capturing a Mass Spectrum visualization.

Sequence Diagram

sequenceDiagram
    participant User as User Code
    participant Accessor as ms_plot Accessor
    participant DataFrame as pandas.DataFrame
    participant Backend as Plot Backend
    participant Figure as Figure Renderer

    User->>Accessor: df.ms_plot(*args, **kwargs)
    Accessor->>Accessor: __call__ receives args/kwargs
    Accessor->>DataFrame: DataFrame.plot(*args, **kwargs)
    DataFrame->>Backend: route to configured plotting backend
    Backend->>Figure: construct figure (traces, layout, annotations)
    Figure-->>Backend: rendered figure object
    Backend-->>DataFrame: return figure
    DataFrame-->>Accessor: return figure
    Accessor-->>User: return figure object
Loading

Suggested reviewers

  • singjc

Poem

🐰 I hopped into code with a curious plot,
A tiny accessor tying dots in a knot,
DataFrame handed the brush with a wink,
Traces and labels in a tidy blink,
Spectra now dance — let's sip carrot tea and gloat!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add .ms_plot accessor to Pandas DataFrames for API parity' clearly and concisely summarizes the main change: adding a new accessor to Pandas DataFrames that matches Polars functionality.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pyopenms_viz/__init__.py`:
- Line 13: The inline "noqa: F401" text is not in canonical comment form and may
be ignored; update the import line that references _pandas_accessor so the
suppression is an actual comment token at the end of the line (e.g. ensure "#
noqa: F401" appears as a proper comment after the explanatory comment) so
linters reliably detect the F401 ignore for the from . import _pandas_accessor
statement.

In `@test/test_pandas_accessor.py`:
- Around line 41-42: The snapshot assertion is unstable because Plotly's
version-dependent layout.template is included; modify the serialization step
before comparing snapshot to remove or normalize figure.layout.template by
calling the Figure.to_dict() representation (use to_dict() instead of
to_plotly_json()) and delete or set figure_dict["layout"].pop("template", None)
(or equivalent) on the exported dict (the variables involved are out and
snapshot and the nested layout.template field) so that snapshot == out compares
a template-free representation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e9eadb01-08c8-42b3-96a5-ddd49ebf0896

📥 Commits

Reviewing files that changed from the base of the PR and between a8d0066 and 864fb5c.

📒 Files selected for processing (4)
  • pyopenms_viz/__init__.py
  • pyopenms_viz/_pandas_accessor.py
  • test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot.json
  • test/test_pandas_accessor.py

Comment thread pyopenms_viz/__init__.py Outdated
Comment thread test/test_pandas_accessor.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a Pandas DataFrame.ms_plot accessor to mirror the “namespace accessor” style API and delegates plotting to DataFrame.plot() so existing Pandas plotting backend configuration continues to work unchanged.

Changes:

  • Added pyopenms_viz._pandas_accessor.PandasPlotAccessor and registered it via @pd.api.extensions.register_dataframe_accessor("ms_plot").
  • Ensured the accessor is registered on import pyopenms_viz via an import-for-side-effects in pyopenms_viz/__init__.py.
  • Added snapshot-based tests (Plotly JSON, Matplotlib PNG, Bokeh HTML) for df.ms_plot(...).

Reviewed changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pyopenms_viz/_pandas_accessor.py Registers DataFrame.ms_plot accessor and delegates calls to DataFrame.plot().
pyopenms_viz/__init__.py Imports the accessor module for registration side-effects.
test/test_pandas_accessor.py Adds a snapshot test exercising the new accessor across configured backends.
test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot[ms_plotly].json Plotly backend expected snapshot for accessor test.
test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot[ms_matplotlib].png Matplotlib backend expected snapshot for accessor test.
test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot[ms_bokeh].html Bokeh backend expected snapshot for accessor test.
test/__snapshots__/test_pandas_accessor/test_pandas_ms_plot_snapshot.json Additional JSON snapshot added (appears redundant vs the parameterized Plotly snapshot).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1 to +5
{
"data": [
{
"line": {
"color": "#4575B4"
@Sanjith1013

Copy link
Copy Markdown
Contributor Author

Hi @singjc,

Just a quick update: I've resolved all the CodeRabbit feedback in the latest commits (fixed the noqa linting format and stripped the volatile Plotly layout.template data to make the new tests resilient across Plotly versions).

However, the CI is still throwing a red check due to two unrelated snapshot test failures in test/test_peakmap_marginals.py (test_peakmap_marginals[ms_bokeh] and test_peakmap_mz_im[ms_bokeh]). It looks like the ms_bokeh backend is generating dynamic HTML UUIDs, which is causing a strict string mismatch against the stored syrupy snapshots. My added tests for the Pandas accessor are passing perfectly.

Let me know if you'd like me to run a global --snapshot-update to sync the Bokeh UUIDs for the repo, or if you prefer to handle that flakiness separately.

@Sanjith1013

Copy link
Copy Markdown
Contributor Author

Hi @singjc,
Let me know if you'd like me to run a global --snapshot-update

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.

2 participants