Skip to content

Commit 4c7c158

Browse files
committed
Merge upstream/main into feature/integrate-lfq-tmt
2 parents 4de63dc + 46bf208 commit 4c7c158

90 files changed

Lines changed: 3755 additions & 3213 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/skills/add-presets.md‎

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Add Parameter Presets
2+
3+
Add or modify parameter presets for a TOPP workflow in `presets.json`.
4+
5+
## Instructions
6+
7+
1. **Ask the user** for:
8+
- Which workflow the presets are for
9+
- Preset names and descriptions
10+
- Parameter values for each preset (TOPP tool parameters and/or custom widget parameters)
11+
12+
2. **Determine the workflow key** from the display name:
13+
- Convert to lowercase, replace spaces with hyphens
14+
- Example: "TOPP Workflow" -> "topp-workflow"
15+
- Example: "Metabolite Analysis" -> "metabolite-analysis"
16+
17+
3. **Read or create `presets.json`** at the repository root. Add entries following this schema:
18+
19+
```json
20+
{
21+
"workflow-name": {
22+
"Preset Name": {
23+
"_description": "Tooltip text shown on hover over the preset button",
24+
"TOPPToolName": {
25+
"algorithm:section:param_name": value
26+
},
27+
"_general": {
28+
"custom-widget-key": value
29+
}
30+
}
31+
}
32+
}
33+
```
34+
35+
4. **Verify the result** by checking that:
36+
- Workflow name key matches the name passed to `WorkflowManager.__init__()` (lowercased, hyphenated)
37+
- TOPP tool names match those used in `input_TOPP()` calls
38+
- Parameter paths use colon-separated format matching the TOPP tool's .ini structure
39+
- `_general` keys match widget keys from `input_widget()` calls
40+
- JSON is valid
41+
42+
## Schema Rules
43+
44+
- **Workflow key**: lowercase, hyphens — must match `WorkflowManager("Display Name", ...)` converted
45+
- **`_description`**: optional tooltip text for the preset button
46+
- **TOPP tool keys**: dictionary name must exactly match the TOPP tool name (e.g., `"FeatureFinderMetabo"`)
47+
- **TOPP parameter paths**: colon-separated, e.g., `"algorithm:common:noise_threshold_int"`
48+
- **`_general`**: overrides for custom `input_widget()` keys (non-TOPP parameters)
49+
- **Keys starting with `_`** are metadata and not applied as tool parameters
50+
51+
## How Presets Work at Runtime
52+
53+
1. Preset buttons auto-appear in `parameter_section()` via `StreamlitUI.preset_buttons()`
54+
2. Only presets matching the current workflow name are displayed
55+
3. Clicking a preset updates `params.json` in the workspace and refreshes the UI
56+
4. If no `presets.json` exists or no presets match, no buttons are shown
57+
58+
## Reference Files
59+
60+
- Existing presets: `presets.json`
61+
- Preset loading: `src/workflow/ParameterManager.py`
62+
- Preset buttons: `src/workflow/StreamlitUI.py` — `preset_buttons()` method
63+
- Documentation: `docs/build_app.md` (Parameter Presets section)
64+
65+
## Example
66+
67+
For a workflow initialized as `super().__init__("Feature Analysis", ...)`:
68+
69+
```json
70+
{
71+
"feature-analysis": {
72+
"High Sensitivity": {
73+
"_description": "Optimized for detecting low-abundance features",
74+
"FeatureFinderMetabo": {
75+
"algorithm:common:noise_threshold_int": 500.0,
76+
"algorithm:common:chrom_peak_snr": 2.0
77+
}
78+
},
79+
"Fast Processing": {
80+
"_description": "Quick analysis with relaxed thresholds",
81+
"FeatureFinderMetabo": {
82+
"algorithm:common:noise_threshold_int": 2000.0
83+
},
84+
"_general": {
85+
"run-python-script": false
86+
}
87+
}
88+
}
89+
}
90+
```
91+
92+
## Checklist
93+
94+
- [ ] Workflow key is lowercase with hyphens, matching the WorkflowManager name
95+
- [ ] Each preset has a descriptive `_description`
96+
- [ ] TOPP tool names match exactly
97+
- [ ] Parameter paths use colon-separated format
98+
- [ ] `presets.json` is valid JSON

‎.claude/skills/add-python-tool.md‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# Add a Python Analysis Tool
2+
3+
Add a custom Python analysis script for MS data processing to `src/python-tools/` with auto-generated UI.
4+
5+
Python tools handle analysis steps that aren't covered by TOPP tools — e.g., exporting consensus features to DataFrames, computing differential expression statistics, custom metabolite annotation, or post-processing identification results.
6+
7+
## Instructions
8+
9+
1. **Ask the user** for:
10+
- Tool name (lowercase, hyphens for spaces)
11+
- What the tool does
12+
- Input/output file types
13+
- Parameters: name, type, default value, constraints
14+
15+
2. **Create the tool script** at `src/python-tools/<name>.py`:
16+
17+
```python
18+
import json
19+
import sys
20+
21+
DEFAULTS = [
22+
# Hidden I/O parameters (always include these)
23+
{"key": "in", "value": [], "help": "Input files.", "hide": True},
24+
{"key": "out", "value": [], "help": "Output files.", "hide": True},
25+
# Visible parameters — examples of each type:
26+
{
27+
"key": "threshold",
28+
"value": 1000.0,
29+
"name": "Intensity Threshold",
30+
"help": "Minimum intensity for filtering.",
31+
"min": 0.0,
32+
"max": 100000.0,
33+
"step_size": 100.0,
34+
},
35+
{
36+
"key": "method",
37+
"value": "default",
38+
"name": "Processing Method",
39+
"options": ["default", "advanced", "custom"],
40+
"help": "Which algorithm to use.",
41+
},
42+
{
43+
"key": "num-features",
44+
"value": 10,
45+
"name": "Number of Features",
46+
"widget_type": "slider",
47+
"min": 1,
48+
"max": 100,
49+
"step_size": 1,
50+
"help": "How many features to report.",
51+
},
52+
{
53+
"key": "advanced-setting",
54+
"value": 5,
55+
"name": "Advanced Setting",
56+
"help": "Only shown in advanced mode.",
57+
"advanced": True,
58+
},
59+
{
60+
"key": "enabled",
61+
"value": True,
62+
"name": "Enable Processing",
63+
},
64+
]
65+
66+
67+
def get_params():
68+
if len(sys.argv) > 1:
69+
with open(sys.argv[1], "r") as f:
70+
return json.load(f)
71+
else:
72+
return {}
73+
74+
75+
if __name__ == "__main__":
76+
params = get_params()
77+
# Tool logic here — read inputs, process, write outputs
78+
```
79+
80+
3. **Wire into a workflow** by adding to the workflow's `configure()` and `execution()` methods:
81+
82+
```python
83+
# In configure():
84+
self.ui.input_python("tool_name")
85+
86+
# In execution():
87+
self.executor.run_python("tool_name", {"in": input_files})
88+
```
89+
90+
## DEFAULTS Metadata Keys
91+
92+
| Key | Required | Type | Description |
93+
|-----|----------|------|-------------|
94+
| `key` | Yes | str | Unique identifier for the parameter |
95+
| `value` | Yes | any | Default value (type determines widget: bool=checkbox, str with options=selectbox, number=number_input) |
96+
| `name` | No | str | Display name in the UI |
97+
| `help` | No | str | Tooltip text |
98+
| `hide` | No | bool | If `True`, parameter is not shown in UI (use for in/out files) |
99+
| `options` | No | list | Valid choices — renders as selectbox |
100+
| `min` | No | number | Minimum value for numeric inputs |
101+
| `max` | No | number | Maximum value for numeric inputs |
102+
| `step_size` | No | number | Step size for numeric inputs |
103+
| `widget_type` | No | str | Override widget type: `"slider"`, `"textarea"`, `"number"`, `"text"`, etc. |
104+
| `advanced` | No | bool | If `True`, only shown when user expands advanced parameters |
105+
106+
## Reference Files
107+
108+
- Example tool: `src/python-tools/example.py`
109+
- Another example: `src/python-tools/export_consensus_feature_df.py`
110+
- UI generation: `src/workflow/StreamlitUI.py` — `input_python()` method
111+
- Execution: `src/workflow/CommandExecutor.py` — `run_python()` method
112+
113+
## Checklist
114+
115+
- [ ] Script created in `src/python-tools/` with DEFAULTS list
116+
- [ ] `get_params()` function and `__main__` block included
117+
- [ ] `in` and `out` keys in DEFAULTS with `"hide": True`
118+
- [ ] Wired into workflow via `self.ui.input_python()` and `self.executor.run_python()`
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Add MS Data Visualization
2+
3+
Add mass spectrometry data visualizations using pyopenms-viz or OpenMS-Insight components.
4+
5+
MS data has specialized visualization needs: mass spectra (m/z vs intensity stick plots), chromatograms (RT vs intensity), 2D peak maps (RT vs m/z heatmaps), isotope patterns, fragment ion annotations, and statistical plots like volcano plots for differential expression.
6+
7+
## Instructions
8+
9+
1. **Ask the user** for:
10+
- What data to visualize (spectra, chromatograms, peak maps, tables, heatmaps)
11+
- Data size expectations (small/medium vs. large datasets with millions of points)
12+
- Whether interactive cross-component linking is needed
13+
14+
2. **Choose the right library**:
15+
16+
| Use Case | Library | Why |
17+
|----------|---------|-----|
18+
| Quick spectrum/chromatogram/peak map plots | **pyopenms-viz** | Simple one-liner API, publication quality |
19+
| Large datasets (millions of points) | **OpenMS-Insight** | Server-side pagination, intelligent downsampling |
20+
| Interactive tables with pagination | **OpenMS-Insight** `Table` | Tabulator.js, CSV export, server-side filtering |
21+
| Cross-linked views (click table row → highlight in plot) | **OpenMS-Insight** | Shared `link_id` across components |
22+
| Standard Plotly plots (bar, scatter, etc.) | **plotly.express** directly | Already available, use with `show_fig()` |
23+
24+
3. **Implement the visualization** in a page or workflow results section.
25+
26+
## pyopenms-viz Patterns
27+
28+
pyopenms-viz extends pandas DataFrames with MS-specific plot accessors. Always use the `plotly` backend for Streamlit.
29+
30+
```python
31+
import pyopenms_viz
32+
from src.common.common import show_fig
33+
34+
# Mass spectrum (stick plot from mz/intensity columns)
35+
fig = df.plot.ms_spectrum(backend="plotly", title="MS1 Spectrum")
36+
show_fig(fig, "spectrum-plot")
37+
38+
# 2D peak map (RT vs m/z, colored by intensity)
39+
fig = df.plot.peak_map(backend="plotly")
40+
show_fig(fig, "peak-map")
41+
42+
# Chromatogram (RT vs intensity)
43+
fig = df.plot.chromatogram(backend="plotly")
44+
show_fig(fig, "chromatogram")
45+
46+
# Mobilogram (ion mobility vs intensity)
47+
fig = df.plot.mobilogram(backend="plotly")
48+
show_fig(fig, "mobilogram")
49+
```
50+
51+
**Key points:**
52+
- DataFrame must have appropriate columns (e.g., `mz`, `intensity` for spectra)
53+
- Always use `backend="plotly"` in Streamlit context
54+
- Use `show_fig()` from `src/common/common.py` for consistent display with download buttons
55+
- Import `pyopenms_viz` to register the plot accessors (even if not used directly)
56+
57+
## OpenMS-Insight Patterns
58+
59+
OpenMS-Insight provides Vue.js-backed interactive components optimized for large MS datasets.
60+
61+
```python
62+
from openms_insight import Table, LinePlot, Heatmap, VolcanoPlot, SequenceView
63+
64+
# Interactive table with server-side pagination
65+
Table(df, key="results-table", page_size=50)
66+
67+
# Stick-style mass spectrum
68+
LinePlot(df, x="mz", y="intensity", key="spectrum-plot")
69+
70+
# 2D heatmap for large datasets (auto-downsampling)
71+
Heatmap(df, x="rt", y="mz", z="intensity", key="peak-heatmap")
72+
73+
# Volcano plot for differential expression
74+
VolcanoPlot(df, x="log2fc", y="neg_log10_pval", key="volcano")
75+
76+
# Peptide sequence with fragment ion annotations
77+
SequenceView(sequence="PEPTIDER", ions=ion_df, key="sequence")
78+
```
79+
80+
### Cross-Component Linking
81+
82+
Link components so selections in one update another:
83+
84+
```python
85+
# Selecting a row in the table highlights the corresponding point in the plot
86+
Table(df, key="linked-table", link_id="feature_id")
87+
LinePlot(df, x="mz", y="intensity", key="linked-plot", link_id="feature_id")
88+
Heatmap(df, x="rt", y="mz", z="intensity", key="linked-heatmap", link_id="feature_id")
89+
```
90+
91+
All components sharing the same `link_id` column are automatically synchronized.
92+
93+
## Integration in Workflow Results
94+
95+
Add visualization to a workflow's `results()` method:
96+
97+
```python
98+
@st.fragment
99+
def results(self) -> None:
100+
result_file = Path(self.workflow_dir, "results", "step-name", "output.tsv")
101+
if result_file.exists():
102+
df = pd.read_csv(result_file, sep="\t")
103+
104+
# pyopenms-viz for spectrum plots
105+
import pyopenms_viz
106+
fig = df.plot.ms_spectrum(backend="plotly")
107+
show_fig(fig, "results-spectrum")
108+
109+
# Or OpenMS-Insight for interactive exploration
110+
from openms_insight import Table
111+
Table(df, key="results-table")
112+
else:
113+
st.warning("No results found. Please run the workflow first.")
114+
```
115+
116+
## Reference Files
117+
118+
- Display utilities: `src/common/common.py` — `show_fig()`, `show_table()`
119+
- Dependencies: `requirements.txt` — `pyopenms-viz`, `openms-insight`
120+
- Example workflow results: `src/Workflow.py` — `results()` method
121+
122+
## Library Repositories
123+
124+
- **pyopenms-viz**: OpenMS/pyopenms-viz — pandas DataFrame `.plot()` extension with matplotlib/bokeh/plotly backends
125+
- **OpenMS-Insight**: t0mdavid-m/openms-insight — Vue.js interactive Streamlit components with caching and downsampling
126+
127+
## Checklist
128+
129+
- [ ] Correct library chosen for the use case
130+
- [ ] Dependencies present in `requirements.txt`
131+
- [ ] `show_fig()` used for pyopenms-viz plots (consistent download/export behavior)
132+
- [ ] `backend="plotly"` specified for all pyopenms-viz plots
133+
- [ ] Unique `key=` values for all OpenMS-Insight components
134+
- [ ] Cross-component linking set up if multiple views of same data

0 commit comments

Comments
 (0)