Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c7b7186
Update parameter files to enhance documentation clarity and accuracy …
Imama-Kainat Mar 7, 2025
f247b28
update the paramters file and add the readthedoc.yml for checking the…
Imama-Kainat Mar 7, 2025
422e289
update the peakmap.rst and tsv file after testing the rendering of do…
Imama-Kainat Mar 7, 2025
b3af95c
Update peakMapPlot.tsv
Imama-Kainat Mar 7, 2025
d6aab12
Update Mobilogram.rst
Imama-Kainat Mar 7, 2025
975bcd1
Update Spectrum.rst
Imama-Kainat Mar 7, 2025
8b6f1ac
Update chromatogramPlot.tsv
Imama-Kainat Mar 7, 2025
a39e1c6
Update Chromatogram.rst
Imama-Kainat Mar 7, 2025
de60795
Update PeakMap.rst
Imama-Kainat Mar 7, 2025
4ea9cca
Update Spectrum.rst
Imama-Kainat Mar 7, 2025
1fd12bb
Merge branch 'OpenMS:main' into ParameterDocUpdation
Imama-Kainat Mar 7, 2025
8724603
updation of rst files
Imama-Kainat Mar 7, 2025
d125573
setting csv files extensiont to config
Imama-Kainat Mar 7, 2025
bd7652c
Merge branch 'OpenMS:main' into ParameterDocUpdation
Imama-Kainat Mar 7, 2025
1ba16cc
Setup TSV auto-update system
Imama-Kainat Mar 7, 2025
58c6e34
Update autoupdate.yml
Imama-Kainat Mar 7, 2025
eda5fe1
Update conf.py
Imama-Kainat Mar 7, 2025
f983ce0
Update autoupdate.yml
Imama-Kainat Mar 7, 2025
735c5e9
Update conf.py
Imama-Kainat Mar 7, 2025
7140c51
Update autoupdate.yml
Imama-Kainat Mar 8, 2025
c05a929
Update conf.py
Imama-Kainat Mar 8, 2025
95c0364
Update autoupdate.yml
Imama-Kainat Mar 8, 2025
20a6f78
Delete .github/workflows/autoupdate.yml
Imama-Kainat Mar 8, 2025
407b95c
Test new parameter
Imama-Kainat Mar 8, 2025
0e27978
Test new parameter
Imama-Kainat Mar 8, 2025
fd2841c
auto updation of tsv files of paramter by changing config file
Imama-Kainat Mar 8, 2025
57b240b
removing the sphinx.ext.csv
Imama-Kainat Mar 8, 2025
ffcafc8
Testing Git Hook: Updated config
Imama-Kainat Mar 10, 2025
1af31a7
Test: Auto-update TSV files on config change
Imama-Kainat Mar 10, 2025
0f7b3c2
Test: Added auto_generated_test_param to BasePlotConfig
Imama-Kainat Mar 10, 2025
512f36f
change check
Imama-Kainat Mar 11, 2025
8f316fc
check
Imama-Kainat Mar 11, 2025
8595e55
Finalized TSV Auto-Update System: Fixed Attribute Extraction, Inherit…
Imama-Kainat Mar 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ docs/gallery
docs/generated
docs/gallery_scripts
docs/_build
.qodo
159 changes: 159 additions & 0 deletions Scripts/update_tsv_docs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""
TSV updater with full inheritance handling, type normalization, and Git hook integration.
Automatically updates TSV files when `_config.py` changes.
"""

import os
import re
import ast
import logging
from pathlib import Path
from typing import Dict, List, Tuple

# Configure logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")

# Paths
CONFIG_PATH = Path("pyopenms_viz/_config.py")
DOCS_DIR = Path("docs/Parameters")

# Mapping dataclasses to TSV file names
CLASS_TO_TSV_MAP = {
"BasePlotConfig": "basePlot.tsv",
"ChromatogramConfig": "chromatogramPlot.tsv",
"MobilogramConfig": "mobilogramPlot.tsv",
"PeakMapConfig": "peakmapPlot.tsv",
"SpectrumConfig": "spectrumPlot.tsv",
}

def normalize_type(type_str: str) -> str:
"""Simplify complex type annotations for consistency."""
type_str = re.sub(r"\bUnion\[([\w\s,]+)\]", r"\1", type_str)
type_str = re.sub(r"\bLiteral\[[^\]]+\]", "str", type_str)
type_str = re.sub(r"\bOptional\[([\w]+)\]", r"\1 | None", type_str)
return type_str.strip()

def parse_docstring(doc: str) -> Dict[str, str]:
"""Extracts descriptions from class docstrings (Sphinx-style)."""
attrs = {}
current_param = None

for line in doc.split("\n"):
line = line.strip()
match = re.match(r":(param|attr)\s+(\w+):\s*(.*)", line)
if match:
current_param = match.group(2)
attrs[current_param] = match.group(3).strip()
elif current_param and line:
attrs[current_param] += f" {line}"

return attrs

def get_all_attributes(class_name, class_definitions, inheritance_map):
"""Recursively retrieves all attributes from a given class, including inherited attributes.
Ignores external classes like `ABC` that do not have a definition in _config.py.
"""
attributes = {}

if class_name in ["ABC", "ABCMeta"]: # Ignore abstract base classes
logging.info(f"⚠️ Skipping abstract base class: {class_name}")
return attributes # Return empty to avoid breaking inheritance

if class_name not in class_definitions:
logging.warning(f"❌ Class {class_name} not found in class definitions!")
return attributes

node = class_definitions[class_name]
logging.info(f"🔍 Extracting attributes for {class_name}")

for stmt in node.body:
if isinstance(stmt, ast.AnnAssign):
name = stmt.target.id if isinstance(stmt.target, ast.Name) else None
if name:
type_annotation = normalize_type(ast.unparse(stmt.annotation))
default = ast.unparse(stmt.value) if stmt.value else "None"
attributes[name] = (default, type_annotation)

# Recursively retrieve attributes from parent classes
for parent in inheritance_map.get(class_name, []):
if parent in ["ABC", "ABCMeta"]: # Ignore ABC base class
logging.info(f"⚠️ Skipping inherited abstract class: {parent}")
continue # Skip processing this parent
parent_attrs = get_all_attributes(parent, class_definitions, inheritance_map)
for attr, values in parent_attrs.items():
if attr not in attributes:
attributes[attr] = values

return attributes


def update_tsv_files():
"""Updates TSV files dynamically, ensuring inheritance is handled properly."""
try:
logging.info("🔍 Reading _config.py...")
config_content = CONFIG_PATH.read_text()
parsed = ast.parse(config_content)

# Extract class definitions and inheritance relationships
inheritance_map = {}
class_definitions = {}

for node in parsed.body:
if isinstance(node, ast.ClassDef):
if node.name in ["ABC", "ABCMeta"]: # Ignore abstract base classes
continue
parent_classes = [base.id for base in node.bases if isinstance(base, ast.Name)]
inheritance_map[node.name] = parent_classes
class_definitions[node.name] = node

logging.info(f"📌 Extracted Classes & Inheritance Map: {inheritance_map}")

updated_files = []
for class_name, tsv_filename in CLASS_TO_TSV_MAP.items():
if class_name in class_definitions:
logging.info(f"🔍 Processing class: {class_name}")

# Retrieve all attributes including inherited ones
all_attributes = get_all_attributes(class_name, class_definitions, inheritance_map)

# Extract docstrings for descriptions
doc = ast.get_docstring(class_definitions[class_name]) or ""
param_docs = parse_docstring(doc)

tsv_path = DOCS_DIR / tsv_filename
logging.info(f"📂 Mapping {class_name} to TSV file: {tsv_path}")

# Read existing TSV content
existing_lines = tsv_path.read_text().strip().split("\n") if tsv_path.exists() else []
existing_params = {line.split("\t")[0]: line for line in existing_lines[1:]} # Skip header

# Prepare new TSV content
header = "Parameter\tDefault\tType\tDescription\n"
lines = []
for name, (default, type_) in all_attributes.items():
description = param_docs.get(name, "")
if name in existing_params:
lines.append(existing_params[name]) # Preserve existing description
else:
lines.append(f"{name}\t{default}\t{type_}\t{description}")

new_content = header + "\n".join(lines)

# Write only if content has changed
if new_content != header + "\n".join(existing_lines):
logging.info(f"✅ Writing to {tsv_path}")
with open(tsv_path, "w") as f:
f.write(new_content)
updated_files.append(tsv_path)

if updated_files:
logging.info(f"✅ Updated {len(updated_files)} TSV files: {', '.join(map(str, updated_files))}")

except FileNotFoundError as e:
logging.error(f"❌ File not found: {e.filename}")
except Exception as e:
logging.error(f"❌ Critical error: {str(e)}")

if __name__ == "__main__":
update_tsv_files()
5 changes: 2 additions & 3 deletions docs/Parameters/Chromatogram.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ Chromatograms can be plotted using kind = chromatogram. In this plot, retention

Parameters
----------

.. csv-table::
:file: chromatogramPlot.tsv
:header-rows: 1
:delim: tab



Example Usage
-------------


.. minigallery::

gallery_scripts/ms_bokeh/plot_chromatogram_ms_bokeh.py
Expand All @@ -23,4 +23,3 @@ Example Usage
gallery_scripts/ms_matplotlib/plot_spyogenes_subplots_ms_matplotlib.py
gallery_scripts/ms_bokeh/plot_spyogenes_subplots_ms_bokeh.py
gallery_scripts/ms_plotly/plot_spyogenes_subplots_ms_plotly.py

4 changes: 1 addition & 3 deletions docs/Parameters/Mobilogram.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Mobilogram
==========

Chromatograms can be plotted using kind = mobilogram. In this plot, ion mobility is on the x-axis and intensity is on the y-axis. The by parameter can be used to separate out different mass traces. Functionally these plots have very similar to chromatograms
Mobilograms are a type of plot used to visualize ion mobility data. In this plot, ion mobility is represented on the x-axis, while intensity is shown on the y-axis. The `by` parameter can be utilized to separate different mass traces. Functionally, mobilograms are similar to chromatograms.

Parameters
----------
Expand All @@ -14,10 +14,8 @@ Parameters
Example Usage
-------------


.. minigallery::

gallery_scripts/ms_bokeh/plot_mobilogram_ms_bokeh.py
gallery_scripts/ms_matplotlib/plot_mobilogram_ms_matplotlib.py
gallery_scripts/ms_plotly/plot_mobilogram_ms_plotly.py

7 changes: 1 addition & 6 deletions docs/Parameters/PeakMap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Peak Map
Peak Maps can be plotted using kind = peakmap. Commonly in this plot, mass-to-charge is on the x-axis, retention time is on the y-axis and intensity is on the z-axis (or represented by color). The x and y axis can be changed based on use case, for example y can also be ion mobility. Using `plot_3d=True` enables 3D plotting. Currently 3D plotting only supported for `ms_matplotlib` and `ms_plotly` backends.



Parameters
----------

Expand All @@ -14,6 +13,7 @@ Parameters
:delim: tab



Example Usage
-------------

Expand All @@ -30,8 +30,3 @@ Example Usage
gallery_scripts/ms_plotly/plot_peakmap_3D_ms_plotly.py
gallery_scripts/ms_matplotlib/plot_peakmap_3D_highlight_peptide_ms_matplotlib.py
gallery_scripts/ms_plotly/plot_peakmap_3D_highlight_peptide_ms_plotly.py





8 changes: 2 additions & 6 deletions docs/Parameters/Spectrum.rst
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
Spectrum
========

A spectrum can be plot using kind = "spectrum". In this plot, mass-to-charge ratio is on the x-axis and intensity is on the y-axis.

A spectrum can be plotted using kind = "spectrum". In this plot, mass-to-charge ratio is on the x-axis and intensity is on the y-axis.

Parameters
----------

.. csv-table:: Chromatogram Options
.. csv-table::
:file: spectrumPlot.tsv
:header-rows: 1
:delim: tab


Example Usage
-------------

.. minigallery::


gallery_scripts/ms_matplotlib/plot_spectrum_ms_matplotlib.py
gallery_scripts/ms_bokeh/plot_spectrum_ms_bokeh.py
gallery_scripts/ms_plotly/plot_spectrum_ms_plotly.py
Expand All @@ -28,4 +25,3 @@ Example Usage
gallery_scripts/ms_matplotlib/plot_investigate_spectrum_binning_ms_matplotlib.py
gallery_scripts/ms_matplotlib/plot_investigate_spectrum_binning_ms_matplotlib.py
gallery_scripts/ms_matplotlib/plot_manuscript_d_fructose_spectrum_prediction_ms_matplotlib.py

46 changes: 32 additions & 14 deletions docs/Parameters/basePlot.tsv
Original file line number Diff line number Diff line change
@@ -1,15 +1,33 @@
Parameter Default Type Description
x* str The column name for x-axis data
y* str The column name for y-axis data
kind* str 'The kind of plot to create. One of: [ “line”, “vline”, scatter”, “chromatogram”, “mobilogram”, “spectrum”, “peak_map”]
by str The column name to group by
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally
relative_intensity False bool Convert y-axis values to relative intensity
height int Height of plot, units dependent on backend.
width int Width of plot in pixels, units dependent on backend.
grid False bool Whether to show grid on the plot
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”]
fig None fig Existing Figure object to plot on
xlabel None str Label for x axis
ylabel None str Label for y axis
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None
kind* "" str The kind of plot to create. One of: ["line", "vline", "scatter", "chromatogram", "mobilogram", "spectrum", "peakmap", "complex"].
x* "" str The column name for x-axis data.
y* "" str The column name for y-axis data.
z "" str The column name for z-axis data (if applicable).
by "" str The column name to group by.
canvas None Any Canvas for the plot. Default is None.
height 500 int Height of plot, units dependent on backend.
width 500 int Width of plot, units dependent on backend.
grid True bool Whether to show grid on the plot.
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar.
title "" str Title of the plot.
xlabel "" str Label for x-axis.
ylabel "" str Label for y-axis.
zlabel "" str Label for z-axis.
x_axis_location "below" str Location of the X-axis.
y_axis_location "left" str Location of the Y-axis.
title_font_size 18 int Font size of the title.
xaxis_label_font_size 16 int Font size of the X-axis label.
yaxis_label_font_size 16 int Font size of the Y-axis label.
zaxis_label_font_size 16 int Font size of the Z-axis label.
xaxis_labelpad 16 int Padding for the X-axis label.
yaxis_labelpad 16 int Padding for the Y-axis label.
zaxis_labelpad 9 int Padding for the Z-axis label.
annotation_font_size 12 int Font size of annotations.
color ColorGenerator str Color for the plot.
plot_3d False bool Whether to plot in 3D.
min_border 0 int Minimum border around the plot.
show_plot True bool Whether to display the plot.
relative_intensity False bool Convert y-axis values to relative intensity.
aggregate_duplicates False bool Whether to aggregate duplicate values.
legend_config LegendConfig | dict Configuration for the legend.
opacity 1.0 float Opacity of the plot.
28 changes: 14 additions & 14 deletions docs/Parameters/chromatogramPlot.tsv
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
Parameter Default Type Description
x* str The column name for x-axis data
y* str The column name for y-axis data
Comment on lines -2 to -3
Copy link
Collaborator

Choose a reason for hiding this comment

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

These options should not be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay i am using this
x* "Retention Time" str X-axis data.
y* "mass-to-charge" str Y-axis data.
in all parameters tsv except base tsv file.
If there is any problem then I will use the same :
x* str The column name for x-axis data
y* str The column name for y-axis data.

by str The column name to group by. Will result in separate line traces per group
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally
annotation_data DataFrame DataFrame of annotation data with columns [‘leftWidth’, ‘rightWidth’]
relative_intensity False bool Convert y-axis values to relative intensity
height int Height of plot, units dependent on backend.
width int Width of plot in pixels, units dependent on backend.
grid False bool Whether to show grid on the plot
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”]
fig None fig Existing figure object to plot on. Useful for matplotlib backend
xlabel None str Label for x axis
ylabel None str Label for y axis
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None
x* "Retention Time" str X-axis data.
y* "mass-to-charge" str Y-axis data.
annotation_data None DataFrame Data for annotations.
annotation_colormap "Dark2" str Colormap for annotations.
annotation_line_width 3 float Width of the annotation lines.
annotation_line_type "solid" str Type of the annotation lines.
grid True bool Whether to display grid lines.
height 500 int Height of the plot.
width 500 int Width of the plot.
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar.
title "Chromatogram" str Title of the plot.
xlabel "Retention Time" str Label for the X-axis.
ylabel "Intensity" str Label for the Y-axis.
show_plot True bool Whether to display the plot.
30 changes: 16 additions & 14 deletions docs/Parameters/mobilogramPlot.tsv
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
Parameter Default Type Description
x* str The column name for x-axis data
y* str The column name for y-axis data
by str The column name to group by. Will result in separate line traces per group
backend str 'Backend to use. One of: [ “ms_matplotlib”, “ms_bokeh”, “ms_plotly” ]. Must be specified if not set globally
annotation_data DataFrame DataFrame of annotation data with columns [‘leftWidth’, ‘rightWidth’]
relative_intensity False bool Convert y-axis values to relative intensity
height int Height of plot, units dependent on backend.
width int Width of plot in pixels, units dependent on backend.
grid False bool Whether to show grid on the plot
toolbar_location “above” Location of toolbar for interactive plots. One of: [“above”, “below”, “left”]
fig None fig Existing figure object to plot on. Useful for matplotlib backend
xlabel None str Label for x axis
ylabel None str Label for y axis
show_plot True bool Whether to display the plot. If plot is not shown, will return the plot object corresponding with the backend. If plot is displayed the method returns None
Comment on lines -2 to -15
Copy link
Collaborator

Choose a reason for hiding this comment

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

These options should all be present. Your script might also have to take into account inheritance of data classes.

x* "Retention Time" str X-axis data.
y* "mass-to-charge" str Y-axis data.
title "Mobilogram" str Title of the plot.
xlabel "Ion Mobility" str Label for the X-axis.
ylabel "Intensity" str Label for the Y-axis.
grid True bool Whether to display grid lines.
height 500 int Height of the plot.
width 500 int Width of the plot.
toolbar_location ["above", "below", "left", "right"] str Location of the toolbar.
annotation_data None DataFrame Data for annotations.
annotation_colormap "Dark2" str Colormap for annotations.
annotation_line_width 3 float Width of the annotation lines.
annotation_line_type "solid" str Type of the annotation lines.
annotation_legend_config None Dict | LegendConfig Configuration for the annotation legend.
legend_config None LegendConfig | dict Configuration for the legend.
show_plot True bool Whether to display the plot.
Loading
Loading