masster 0.3.0__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of masster might be problematic. Click here for more details.

Files changed (80) hide show
  1. {masster-0.3.0 → masster-0.3.1}/PKG-INFO +1 -1
  2. {masster-0.3.0 → masster-0.3.1}/pyproject.toml +177 -177
  3. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/plot.py +111 -36
  4. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/sample.py +7 -5
  5. {masster-0.3.0 → masster-0.3.1}/src/masster/study/h5.py +8 -0
  6. {masster-0.3.0 → masster-0.3.1}/src/masster/study/helpers.py +87 -24
  7. {masster-0.3.0 → masster-0.3.1}/src/masster/study/load.py +38 -8
  8. {masster-0.3.0 → masster-0.3.1}/src/masster/study/save.py +22 -10
  9. {masster-0.3.0 → masster-0.3.1}/src/masster/study/study.py +11 -5
  10. {masster-0.3.0 → masster-0.3.1}/src/masster/study/study5_schema.json +6 -0
  11. {masster-0.3.0 → masster-0.3.1}/tests/test_chromatogram.py +15 -10
  12. {masster-0.3.0 → masster-0.3.1}/uv.lock +1 -1
  13. {masster-0.3.0 → masster-0.3.1}/.github/workflows/publish.yml +0 -0
  14. {masster-0.3.0 → masster-0.3.1}/.github/workflows/security.yml +0 -0
  15. {masster-0.3.0 → masster-0.3.1}/.github/workflows/test.yml +0 -0
  16. {masster-0.3.0 → masster-0.3.1}/.gitignore +0 -0
  17. {masster-0.3.0 → masster-0.3.1}/.pre-commit-config.yaml +0 -0
  18. {masster-0.3.0 → masster-0.3.1}/LICENSE +0 -0
  19. {masster-0.3.0 → masster-0.3.1}/Makefile +0 -0
  20. {masster-0.3.0 → masster-0.3.1}/README.md +0 -0
  21. {masster-0.3.0 → masster-0.3.1}/TESTING.md +0 -0
  22. {masster-0.3.0 → masster-0.3.1}/demo/example_batch_process.py +0 -0
  23. {masster-0.3.0 → masster-0.3.1}/demo/example_sample_process.py +0 -0
  24. {masster-0.3.0 → masster-0.3.1}/src/masster/__init__.py +0 -0
  25. {masster-0.3.0 → masster-0.3.1}/src/masster/_version.py +0 -0
  26. {masster-0.3.0 → masster-0.3.1}/src/masster/chromatogram.py +0 -0
  27. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.featureXML +0 -0
  28. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.mzML +0 -0
  29. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.sample5 +0 -0
  30. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.timeseries.data +0 -0
  31. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff +0 -0
  32. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff.scan +0 -0
  33. {masster-0.3.0 → masster-0.3.1}/src/masster/data/examples/2025_01_14_VW_7600_LpMx_DBS_CID_2min_TOP15_030msecMS1_005msecReac_CE35_DBS-ON_3.wiff2 +0 -0
  34. {masster-0.3.0 → masster-0.3.1}/src/masster/logger.py +0 -0
  35. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/__init__.py +0 -0
  36. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/__init__.py +0 -0
  37. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/find_adducts_def.py +0 -0
  38. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/find_features_def.py +0 -0
  39. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/find_ms2_def.py +0 -0
  40. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/get_spectrum_def.py +0 -0
  41. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/defaults/sample_def.py +0 -0
  42. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/h5.py +0 -0
  43. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/helpers.py +0 -0
  44. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/lib.py +0 -0
  45. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/load.py +0 -0
  46. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/parameters.py +0 -0
  47. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/processing.py +0 -0
  48. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/quant.py +0 -0
  49. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/sample5_schema.json +0 -0
  50. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/save.py +0 -0
  51. {masster-0.3.0 → masster-0.3.1}/src/masster/sample/sciex.py +0 -0
  52. {masster-0.3.0 → masster-0.3.1}/src/masster/spectrum.py +0 -0
  53. {masster-0.3.0 → masster-0.3.1}/src/masster/study/__init__.py +0 -0
  54. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/__init__.py +0 -0
  55. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/align_def.py +0 -0
  56. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/export_def.py +0 -0
  57. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/fill_chrom_def.py +0 -0
  58. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/fill_def.py +0 -0
  59. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/find_consensus_def.py +0 -0
  60. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/find_ms2_def.py +0 -0
  61. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/integrate_chrom_def.py +0 -0
  62. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/integrate_def.py +0 -0
  63. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/merge_def.py +0 -0
  64. {masster-0.3.0 → masster-0.3.1}/src/masster/study/defaults/study_def.py +0 -0
  65. {masster-0.3.0 → masster-0.3.1}/src/masster/study/export.py +0 -0
  66. {masster-0.3.0 → masster-0.3.1}/src/masster/study/helpers_optimized.py +0 -0
  67. {masster-0.3.0 → masster-0.3.1}/src/masster/study/parameters.py +0 -0
  68. {masster-0.3.0 → masster-0.3.1}/src/masster/study/plot.py +0 -0
  69. {masster-0.3.0 → masster-0.3.1}/src/masster/study/processing.py +0 -0
  70. {masster-0.3.0 → masster-0.3.1}/tests/conftest.py +0 -0
  71. {masster-0.3.0 → masster-0.3.1}/tests/test_defaults.py +0 -0
  72. {masster-0.3.0 → masster-0.3.1}/tests/test_imports.py +0 -0
  73. {masster-0.3.0 → masster-0.3.1}/tests/test_integration.py +0 -0
  74. {masster-0.3.0 → masster-0.3.1}/tests/test_logger.py +0 -0
  75. {masster-0.3.0 → masster-0.3.1}/tests/test_parameters.py +0 -0
  76. {masster-0.3.0 → masster-0.3.1}/tests/test_sample.py +0 -0
  77. {masster-0.3.0 → masster-0.3.1}/tests/test_spectrum.py +0 -0
  78. {masster-0.3.0 → masster-0.3.1}/tests/test_study.py +0 -0
  79. {masster-0.3.0 → masster-0.3.1}/tests/test_version.py +0 -0
  80. {masster-0.3.0 → masster-0.3.1}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: masster
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Mass spectrometry data analysis package
5
5
  Project-URL: homepage, https://github.com/zamboni-lab/masster
6
6
  Project-URL: repository, https://github.com/zamboni-lab/masster
@@ -1,141 +1,141 @@
1
-
2
- [project]
3
- name = "masster"
4
- version = "0.3.0"
5
- description = "Mass spectrometry data analysis package"
6
- authors = [
7
- { name = "Zamboni Lab" }
8
- ]
9
- license = { file = "LICENSE" }
10
- readme = "README.md"
11
- requires-python = ">=3.11"
12
- keywords = ["mass spectrometry", "metabolomics", "lc-ms", "chromatography"]
13
- classifiers = [
14
- "Development Status :: 3 - Alpha",
15
- "Intended Audience :: Science/Research",
16
- "License :: OSI Approved :: GNU Affero General Public License v3",
17
- "Operating System :: OS Independent",
18
- "Programming Language :: Python :: 3",
19
- "Programming Language :: Python :: 3.11",
20
- "Programming Language :: Python :: 3.12",
21
- "Programming Language :: Python :: 3.13",
22
- "Topic :: Scientific/Engineering :: Bio-Informatics",
23
- "Topic :: Scientific/Engineering :: Chemistry"
24
- ]
25
- urls.homepage = "https://github.com/zamboni-lab/masster"
26
- urls.repository = "https://github.com/zamboni-lab/masster"
27
- urls.documentation = "https://github.com/zamboni-lab/masster#readme"
28
- dependencies = [
29
- "alphabase>=1.0.0",
30
- "alpharaw>=0.4.8",
31
- "altair>=5.5.0",
32
- "bokeh>=3.7.3",
33
- "datashader>=0.18.1",
34
- "python-dotenv>=1.0.0",
35
- "holoviews>=1.21.0",
36
- "h5py>=3.14.0",
37
- "hvplot>=0.11.3",
38
- "loguru>=0.7.3",
39
- "numpy>=2.0.0",
40
- "marimo>=0.14.16",
41
- "matchms>=0.30.2",
42
- "matplotlib>=3.8.0",
43
- "pandas>=2.2.0",
44
- "panel>=1.7.0",
45
- "plotly>=5.15.0",
46
- "polars>=1.0.0",
47
- "pyopenms>=3.3.0",
48
- "pyteomics>=4.7.0",
49
- "pythonnet>=3.0.0",
50
- "scipy>=1.12.0",
51
- "simple-parsing>=0.1.7",
52
- "tqdm>=4.65.0",
53
- "ipykernel>=6.30.0",
54
- "openpyxl>=3.1.5",
55
- ]
56
-
57
- [project.optional-dependencies]
58
- dev = [
59
- "pytest>=7.0.0",
60
- "pytest-cov>=4.0.0",
61
- "pytest-mock>=3.10.0",
62
- "black>=23.0.0",
63
- "flake8>=5.0.0",
64
- "mypy>=1.0.0",
65
- "pre-commit>=3.0.0",
66
- "twine>=4.0.0",
67
- "build>=0.10.0",
68
- "safety>=2.0.0",
69
- "bandit>=1.7.0"
70
- ]
71
- docs = [
72
- "sphinx>=5.0.0",
73
- "sphinx-rtd-theme>=1.2.0",
74
- "sphinxcontrib-napoleon>=0.7"
75
- ]
76
- test = [
77
- "pytest>=7.0.0",
78
- "pytest-cov>=4.0.0",
79
- "pytest-mock>=3.10.0",
80
- "coverage>=7.0.0"
81
- ]
82
-
83
- [project.scripts]
84
- masster-version = "masster._version:main"
85
-
86
- [build-system]
87
- requires = ["hatchling>=1.18.0"]
88
- build-backend = "hatchling.build"
89
-
90
- # Testing configuration
91
- [tool.pytest.ini_options]
92
- testpaths = ["tests"]
93
- python_files = ["test_*.py"]
94
- python_classes = ["Test*"]
95
- python_functions = ["test_*"]
96
- addopts = [
97
- "--strict-markers",
98
- "--strict-config",
99
- "--verbose",
100
- "--cov=masster",
101
- "--cov-report=term-missing",
102
- "--cov-report=html",
103
- "--cov-report=xml",
104
- ]
105
- markers = [
106
- "slow: marks tests as slow (deselect with '-m \"not slow\"')",
107
- "integration: marks tests as integration tests",
108
- ]
109
- filterwarnings = [
110
- "error",
111
- "ignore::UserWarning",
112
- "ignore::DeprecationWarning",
113
- ]
114
-
115
- # Coverage configuration
116
- [tool.coverage.run]
117
- source = ["masster"]
118
- omit = [
119
- "*/tests/*",
120
- "*/test_*.py",
121
- "masster/_version.py",
122
- ]
123
-
124
- [tool.coverage.report]
125
- exclude_lines = [
126
- "pragma: no cover",
127
- "def __repr__",
128
- "raise AssertionError",
129
- "raise NotImplementedError",
130
- "if __name__ == .__main__.:",
131
- "if TYPE_CHECKING:",
132
- ]
133
-
134
- # Black configuration
135
- [tool.black]
136
- line-length = 88
137
- target-version = ['py311']
138
- include = '\.pyi?$'
1
+
2
+ [project]
3
+ name = "masster"
4
+ version = "0.3.1"
5
+ description = "Mass spectrometry data analysis package"
6
+ authors = [
7
+ { name = "Zamboni Lab" }
8
+ ]
9
+ license = { file = "LICENSE" }
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+ keywords = ["mass spectrometry", "metabolomics", "lc-ms", "chromatography"]
13
+ classifiers = [
14
+ "Development Status :: 3 - Alpha",
15
+ "Intended Audience :: Science/Research",
16
+ "License :: OSI Approved :: GNU Affero General Public License v3",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Scientific/Engineering :: Bio-Informatics",
23
+ "Topic :: Scientific/Engineering :: Chemistry"
24
+ ]
25
+ urls.homepage = "https://github.com/zamboni-lab/masster"
26
+ urls.repository = "https://github.com/zamboni-lab/masster"
27
+ urls.documentation = "https://github.com/zamboni-lab/masster#readme"
28
+ dependencies = [
29
+ "alphabase>=1.0.0",
30
+ "alpharaw>=0.4.8",
31
+ "altair>=5.5.0",
32
+ "bokeh>=3.7.3",
33
+ "datashader>=0.18.1",
34
+ "python-dotenv>=1.0.0",
35
+ "holoviews>=1.21.0",
36
+ "h5py>=3.14.0",
37
+ "hvplot>=0.11.3",
38
+ "loguru>=0.7.3",
39
+ "numpy>=2.0.0",
40
+ "marimo>=0.14.16",
41
+ "matchms>=0.30.2",
42
+ "matplotlib>=3.8.0",
43
+ "pandas>=2.2.0",
44
+ "panel>=1.7.0",
45
+ "plotly>=5.15.0",
46
+ "polars>=1.0.0",
47
+ "pyopenms>=3.3.0",
48
+ "pyteomics>=4.7.0",
49
+ "pythonnet>=3.0.0",
50
+ "scipy>=1.12.0",
51
+ "simple-parsing>=0.1.7",
52
+ "tqdm>=4.65.0",
53
+ "ipykernel>=6.30.0",
54
+ "openpyxl>=3.1.5",
55
+ ]
56
+
57
+ [project.optional-dependencies]
58
+ dev = [
59
+ "pytest>=7.0.0",
60
+ "pytest-cov>=4.0.0",
61
+ "pytest-mock>=3.10.0",
62
+ "black>=23.0.0",
63
+ "flake8>=5.0.0",
64
+ "mypy>=1.0.0",
65
+ "pre-commit>=3.0.0",
66
+ "twine>=4.0.0",
67
+ "build>=0.10.0",
68
+ "safety>=2.0.0",
69
+ "bandit>=1.7.0"
70
+ ]
71
+ docs = [
72
+ "sphinx>=5.0.0",
73
+ "sphinx-rtd-theme>=1.2.0",
74
+ "sphinxcontrib-napoleon>=0.7"
75
+ ]
76
+ test = [
77
+ "pytest>=7.0.0",
78
+ "pytest-cov>=4.0.0",
79
+ "pytest-mock>=3.10.0",
80
+ "coverage>=7.0.0"
81
+ ]
82
+
83
+ [project.scripts]
84
+ masster-version = "masster._version:main"
85
+
86
+ [build-system]
87
+ requires = ["hatchling>=1.18.0"]
88
+ build-backend = "hatchling.build"
89
+
90
+ # Testing configuration
91
+ [tool.pytest.ini_options]
92
+ testpaths = ["tests"]
93
+ python_files = ["test_*.py"]
94
+ python_classes = ["Test*"]
95
+ python_functions = ["test_*"]
96
+ addopts = [
97
+ "--strict-markers",
98
+ "--strict-config",
99
+ "--verbose",
100
+ "--cov=masster",
101
+ "--cov-report=term-missing",
102
+ "--cov-report=html",
103
+ "--cov-report=xml",
104
+ ]
105
+ markers = [
106
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
107
+ "integration: marks tests as integration tests",
108
+ ]
109
+ filterwarnings = [
110
+ "error",
111
+ "ignore::UserWarning",
112
+ "ignore::DeprecationWarning",
113
+ ]
114
+
115
+ # Coverage configuration
116
+ [tool.coverage.run]
117
+ source = ["masster"]
118
+ omit = [
119
+ "*/tests/*",
120
+ "*/test_*.py",
121
+ "masster/_version.py",
122
+ ]
123
+
124
+ [tool.coverage.report]
125
+ exclude_lines = [
126
+ "pragma: no cover",
127
+ "def __repr__",
128
+ "raise AssertionError",
129
+ "raise NotImplementedError",
130
+ "if __name__ == .__main__.:",
131
+ "if TYPE_CHECKING:",
132
+ ]
133
+
134
+ # Black configuration
135
+ [tool.black]
136
+ line-length = 88
137
+ target-version = ['py311']
138
+ include = '\.pyi?$'
139
139
  extend-exclude = '''
140
140
  /(
141
141
  # directories
@@ -148,42 +148,42 @@ extend-exclude = '''
148
148
  | build
149
149
  | dist
150
150
  )/
151
- '''
152
-
153
- # MyPy configuration
154
- [tool.mypy]
155
- python_version = "3.11"
156
- warn_return_any = true
157
- warn_unused_configs = true
158
- disallow_untyped_defs = false
159
- disallow_incomplete_defs = false
160
- check_untyped_defs = true
161
- disallow_untyped_decorators = false
162
- no_implicit_optional = true
163
- warn_redundant_casts = true
164
- warn_unused_ignores = true
165
- warn_no_return = true
166
- warn_unreachable = true
167
- strict_equality = true
168
- ignore_missing_imports = true
169
-
170
- # Flake8 configuration
171
- [tool.flake8]
172
- max-line-length = 88
173
- extend-ignore = ["E203", "W503"]
174
- exclude = [
175
- ".git",
176
- "__pycache__",
177
- "docs",
178
- "build",
179
- "dist",
180
- ".eggs",
181
- "*.egg-info",
182
- ".venv",
183
- "venv",
184
- ]
185
-
186
- # Bandit configuration
187
- [tool.bandit]
188
- exclude_dirs = ["tests"]
189
- skips = ["B101", "B601"]
151
+ '''
152
+
153
+ # MyPy configuration
154
+ [tool.mypy]
155
+ python_version = "3.11"
156
+ warn_return_any = true
157
+ warn_unused_configs = true
158
+ disallow_untyped_defs = false
159
+ disallow_incomplete_defs = false
160
+ check_untyped_defs = true
161
+ disallow_untyped_decorators = false
162
+ no_implicit_optional = true
163
+ warn_redundant_casts = true
164
+ warn_unused_ignores = true
165
+ warn_no_return = true
166
+ warn_unreachable = true
167
+ strict_equality = true
168
+ ignore_missing_imports = true
169
+
170
+ # Flake8 configuration
171
+ [tool.flake8]
172
+ max-line-length = 88
173
+ extend-ignore = ["E203", "W503"]
174
+ exclude = [
175
+ ".git",
176
+ "__pycache__",
177
+ "docs",
178
+ "build",
179
+ "dist",
180
+ ".eggs",
181
+ "*.egg-info",
182
+ ".venv",
183
+ "venv",
184
+ ]
185
+
186
+ # Bandit configuration
187
+ [tool.bandit]
188
+ exclude_dirs = ["tests"]
189
+ skips = ["B101", "B601"]
@@ -22,13 +22,13 @@ Dependencies:
22
22
  - `numpy`: For numerical computations.
23
23
 
24
24
  Functions:
25
- - `plot_eic()`: Generate extracted ion chromatograms with feature overlays.
25
+ - `plot_chrom()`: Generate chromatograms with feature overlays.
26
26
  - `plot_2d()`: Create 2D mass spectrometry data visualizations.
27
27
  - `plot_features()`: Visualize detected features in retention time vs m/z space.
28
28
  - Various utility functions for plot styling and configuration.
29
29
 
30
30
  Supported Plot Types:
31
- - Extracted Ion Chromatograms (EIC)
31
+ - Chromatograms
32
32
  - Total Ion Chromatograms (TIC)
33
33
  - Base Peak Chromatograms (BPC)
34
34
  - 2D intensity maps (RT vs m/z)
@@ -63,7 +63,74 @@ from matplotlib.colors import rgb2hex
63
63
  hv.extension("bokeh")
64
64
 
65
65
 
66
- def plot_eic(
66
+ def _is_notebook_environment():
67
+ """
68
+ Detect if code is running in a notebook environment (Jupyter, JupyterLab, or Marimo).
69
+
70
+ Returns:
71
+ bool: True if running in a notebook, False otherwise
72
+ """
73
+ try:
74
+ # Check for Jupyter/JupyterLab
75
+ from IPython import get_ipython
76
+ if get_ipython() is not None:
77
+ # Check if we're in a notebook context
78
+ shell = get_ipython().__class__.__name__
79
+ if shell in ['ZMQInteractiveShell', 'Shell']: # Jupyter notebook/lab
80
+ return True
81
+
82
+ # Check for Marimo
83
+ import sys
84
+ if 'marimo' in sys.modules:
85
+ return True
86
+
87
+ # Additional check for notebook environments
88
+ if hasattr(__builtins__, '__IPYTHON__') or hasattr(__builtins__, '_ih'):
89
+ return True
90
+
91
+ except ImportError:
92
+ pass
93
+
94
+ return False
95
+
96
+
97
+ def _display_plot(plot_object, layout=None):
98
+ """
99
+ Display a plot object in the appropriate way based on the environment.
100
+
101
+ Args:
102
+ plot_object: The plot object to display (holoviews overlay, etc.)
103
+ layout: Optional panel layout object
104
+
105
+ Returns:
106
+ The layout object if in notebook environment, None otherwise
107
+ """
108
+ if _is_notebook_environment():
109
+ # Display inline in notebook
110
+ try:
111
+ # For Jupyter notebooks, just return the plot object -
112
+ # holoviews will handle the display automatically
113
+ return plot_object
114
+ except Exception:
115
+ # Fallback to panel display for other notebook environments
116
+ if layout is not None:
117
+ return layout
118
+ else:
119
+ # Create a simple layout if none provided
120
+ simple_layout = panel.Column(plot_object)
121
+ return simple_layout
122
+ else:
123
+ # Display in browser (original behavior)
124
+ if layout is not None:
125
+ layout.show()
126
+ else:
127
+ # Create a simple layout for browser display
128
+ simple_layout = panel.Column(plot_object)
129
+ simple_layout.show()
130
+ return None
131
+
132
+
133
+ def plot_chrom(
67
134
  self,
68
135
  feature_uid=None,
69
136
  filename=None,
@@ -74,16 +141,16 @@ def plot_eic(
74
141
  link_x=False,
75
142
  ):
76
143
  """
77
- Plot Extracted Ion Chromatograms (EICs) for one or more features using MS1 data and feature metadata.
144
+ Plot chromatograms for one or more features using MS1 data and feature metadata.
78
145
 
79
146
  This function filters MS1 data based on retention time (rt) and mass-to-charge ratio (mz) windows
80
- derived from feature information in `features_df`. It then generates interactive EIC plots using
147
+ derived from feature information in `features_df`. It then generates interactive chromatogram plots using
81
148
  HoloViews, with feature retention time windows annotated. Plots can be displayed interactively or
82
149
  saved to a file.
83
150
 
84
151
  Parameters:
85
152
  feature_uid (int or list of int, optional):
86
- Feature identifier(s) for EIC generation. If None, EICs for all features in `features_df` are plotted.
153
+ Feature identifier(s) for chromatogram generation. If None, chromatograms for all features in `features_df` are plotted.
87
154
  filename (str, optional):
88
155
  Output file path. If ending with `.html`, saves as interactive HTML; otherwise, saves as PNG.
89
156
  If not provided, displays the plot interactively.
@@ -96,7 +163,7 @@ def plot_eic(
96
163
  mz_tol_factor_plot (float, default=1):
97
164
  m/z time tolerance factor.
98
165
  link_x (bool, default=True):
99
- If True, links the x-axes (retention time) across all EIC subplots.
166
+ If True, links the x-axes (retention time) across all chromatogram subplots.
100
167
 
101
168
  Returns:
102
169
  None
@@ -106,7 +173,7 @@ def plot_eic(
106
173
  - Aggregates MS1 intensities by retention time.
107
174
  - Utilizes HoloViews for visualization and Panel for layout/display.
108
175
  """
109
- # plots the EIC for a given feature id
176
+ # plots the chromatogram for a given feature id
110
177
  # If rt or mz are not provided, they are extracted from features_df using the supplied feature id (feature_uid)
111
178
 
112
179
  feature_uids = feature_uid
@@ -121,7 +188,7 @@ def plot_eic(
121
188
 
122
189
  # make sure feature_uid is a list of integers
123
190
 
124
- eic_plots = []
191
+ chrom_plots = []
125
192
  feature_uids = feats["feature_uid"].values.tolist()
126
193
  mz_tol_plot = mz_tol * mz_tol_factor_plot
127
194
  rt_tol_plot = rt_tol * rt_tol_factor_plot
@@ -137,29 +204,29 @@ def plot_eic(
137
204
  mz_end = feature_row["mz_end"].values[0]
138
205
 
139
206
  # filter self.ms1_df with rt_start, rt_end, mz_start, mz_end
140
- eic_df = self.ms1_df.filter(
207
+ chrom_df = self.ms1_df.filter(
141
208
  pl.col("rt") >= rt_start - rt_tol_plot,
142
209
  pl.col("rt") <= rt_end + rt_tol_plot,
143
210
  )
144
- eic_df = eic_df.filter(
211
+ chrom_df = chrom_df.filter(
145
212
  pl.col("mz") >= mz_start - mz_tol_plot,
146
213
  pl.col("mz") <= mz_end + mz_tol_plot,
147
214
  )
148
215
 
149
- if eic_df.is_empty():
216
+ if chrom_df.is_empty():
150
217
  print("No MS1 data found in the specified window.")
151
218
  continue
152
219
 
153
220
  # convert to pandas DataFrame
154
- eic_df = eic_df.to_pandas()
221
+ chrom_df = chrom_df.to_pandas()
155
222
  # aggregate all points with the same rt using the sum of inty
156
- eic_df = eic_df.groupby("rt").agg({"inty": "sum"}).reset_index()
223
+ chrom_df = chrom_df.groupby("rt").agg({"inty": "sum"}).reset_index()
157
224
  yname = f"inty_{feature_uid}"
158
- eic_df.rename(columns={"inty": yname}, inplace=True)
225
+ chrom_df.rename(columns={"inty": yname}, inplace=True)
159
226
 
160
- # Plot the EIC using bokeh and ensure axes are independent by setting axiswise=True
161
- eic = hv.Curve(eic_df, kdims=["rt"], vdims=[yname]).opts(
162
- title=f"EIC for feature {feature_uid}, mz = {mz:.4f}",
227
+ # Plot the chromatogram using bokeh and ensure axes are independent by setting axiswise=True
228
+ chrom = hv.Curve(chrom_df, kdims=["rt"], vdims=[yname]).opts(
229
+ title=f"Chromatogram for feature {feature_uid}, mz = {mz:.4f}",
163
230
  xlabel="Retention time (s)",
164
231
  ylabel="Intensity",
165
232
  width=1000,
@@ -170,13 +237,13 @@ def plot_eic(
170
237
  )
171
238
 
172
239
  # Add vertical lines at the start and end of the retention time
173
- eic = eic * hv.VLine(rt_start).opts(
240
+ chrom = chrom * hv.VLine(rt_start).opts(
174
241
  color="blue",
175
242
  line_width=1,
176
243
  line_dash="dashed",
177
244
  axiswise=True,
178
245
  )
179
- eic = eic * hv.VLine(rt_end).opts(
246
+ chrom = chrom * hv.VLine(rt_end).opts(
180
247
  color="blue",
181
248
  line_width=1,
182
249
  line_dash="dashed",
@@ -184,12 +251,12 @@ def plot_eic(
184
251
  )
185
252
 
186
253
  # Append the subplot without linking axes
187
- eic_plots.append(eic)
254
+ chrom_plots.append(chrom)
188
255
  if link_x:
189
- # Create a layout with shared x-axis for all EIC plots
190
- layout = hv.Layout(eic_plots).opts(shared_axes=True)
256
+ # Create a layout with shared x-axis for all chromatogram plots
257
+ layout = hv.Layout(chrom_plots).opts(shared_axes=True)
191
258
  else:
192
- layout = hv.Layout(eic_plots).opts(shared_axes=False)
259
+ layout = hv.Layout(chrom_plots).opts(shared_axes=False)
193
260
 
194
261
  layout = layout.cols(1)
195
262
  layout = panel.Column(layout)
@@ -201,8 +268,8 @@ def plot_eic(
201
268
  # save the panel layout as a png
202
269
  hv.save(layout, filename, fmt="png")
203
270
  else:
204
- # Display the panel layout
205
- layout.show()
271
+ # Check if we're in a notebook environment and display appropriately
272
+ return _display_plot(layout.object, layout)
206
273
 
207
274
 
208
275
  def plot_2d(
@@ -513,8 +580,8 @@ def plot_2d(
513
580
  # save the panel layout as a png
514
581
  hv.save(overlay, filename, fmt="png")
515
582
  else:
516
- # Display the panel layout
517
- layout.show()
583
+ # Check if we're in a notebook environment and display appropriately
584
+ return _display_plot(overlay, layout)
518
585
 
519
586
 
520
587
  def plot_2d_oracle(
@@ -922,8 +989,8 @@ def plot_2d_oracle(
922
989
  # save the panel layout as a png
923
990
  hv.save(overlay, filename, fmt="png")
924
991
  else:
925
- # Display the panel layout
926
- layout.show()
992
+ # Check if we're in a notebook environment and display appropriately
993
+ return _display_plot(overlay, layout)
927
994
 
928
995
 
929
996
  def plot_ms2_eic(
@@ -1070,7 +1137,9 @@ def plot_ms2_eic(
1070
1137
  else:
1071
1138
  hv.save(layout, filename, fmt="png")
1072
1139
  else:
1073
- panel.panel(layout).show()
1140
+ # Check if we're in a notebook environment and display appropriately
1141
+ layout_obj = panel.panel(layout)
1142
+ return _display_plot(layout, layout_obj)
1074
1143
 
1075
1144
 
1076
1145
  def plot_ms2_cycle(
@@ -1290,8 +1359,8 @@ def plot_ms2_cycle(
1290
1359
  # save the panel layout as a png
1291
1360
  hv.save(overlay, filename, fmt="png")
1292
1361
  else:
1293
- # Display the panel layout
1294
- layout.show()
1362
+ # Check if we're in a notebook environment and display appropriately
1363
+ return _display_plot(overlay, layout)
1295
1364
 
1296
1365
 
1297
1366
  def plot_ms2_q1(
@@ -1393,7 +1462,9 @@ def plot_ms2_q1(
1393
1462
  else:
1394
1463
  hv.save(layout, filename, fmt="png")
1395
1464
  else:
1396
- panel.panel(layout).show()
1465
+ # Check if we're in a notebook environment and display appropriately
1466
+ layout_obj = panel.panel(layout)
1467
+ return _display_plot(layout, layout_obj)
1397
1468
 
1398
1469
 
1399
1470
  def plot_dda_stats(
@@ -1468,7 +1539,9 @@ def plot_dda_stats(
1468
1539
  else:
1469
1540
  hv.save(layout, filename, fmt="png")
1470
1541
  else:
1471
- panel.panel(layout).show()
1542
+ # Check if we're in a notebook environment and display appropriately
1543
+ layout_obj = panel.panel(layout)
1544
+ return _display_plot(layout, layout_obj)
1472
1545
 
1473
1546
 
1474
1547
  def plot_feature_stats(
@@ -1584,7 +1657,9 @@ def plot_feature_stats(
1584
1657
  else:
1585
1658
  hv.save(layout, filename, fmt="png")
1586
1659
  else:
1587
- panel.panel(layout).show()
1660
+ # Check if we're in a notebook environment and display appropriately
1661
+ layout_obj = panel.panel(layout)
1662
+ return _display_plot(layout, layout_obj)
1588
1663
 
1589
1664
 
1590
1665
  def plot_tic(