Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,22 @@ jobs:
- uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- uses: actions/setup-node@v4
with:
node-version: "21"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
# OpenMS-Insight (Phase-3) is not on PyPI: build it from the migration branch
# (Vue bundle + Python) and install from source -- mirrors the Dockerfiles.
git clone -b claude/kind-heisenberg-u6dVm --single-branch --depth 1 \
https://github.com/t0mdavid-m/openms-insight.git /tmp/openms-insight
( cd /tmp/openms-insight/js-component && npm install && npm run build )
mkdir -p /tmp/openms-insight/openms_insight/js-component
cp -r /tmp/openms-insight/js-component/dist \
/tmp/openms-insight/openms_insight/js-component/dist
pip install /tmp/openms-insight
pip install -r requirements.txt # test with requirements file so can easily bump with dependabot
pip install pytest fakeredis
- name: Test
Expand Down
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,21 @@ RUN mkdir /thirdparty && \
chmod -R +x /thirdparty
ENV PATH="/thirdparty/LuciPHOr2:/thirdparty/MSGFPlus:/thirdparty/Sirius:/thirdparty/ThermoRawFileParser:/thirdparty/Comet:/thirdparty/Fido:/thirdparty/MaRaCluster:/thirdparty/MyriMatch:/thirdparty/OMSSA:/thirdparty/Percolator:/thirdparty/SpectraST:/thirdparty/XTandem:/thirdparty/crux:${PATH}"

# Build the OpenMS-Insight package (Python + Vue bundle) from the migration branch.
# Insight's Vue dist is gitignored and it has no pip build hook, so build the bundle
# here and sync it into the package tree; the compile-openms stage pip-installs it.
FROM node:21 AS insight-build
ARG INSIGHT_REPO=https://github.com/t0mdavid-m/openms-insight.git
ARG INSIGHT_BRANCH=claude/kind-heisenberg-u6dVm
ADD https://api.github.com/repos/t0mdavid-m/openms-insight/git/refs/heads/${INSIGHT_BRANCH} insight-ref.json
RUN git clone -b ${INSIGHT_BRANCH} --single-branch ${INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install && npm run build
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& rm -rf /openms-insight/openms_insight/js-component/dist \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist \
&& rm -rf /openms-insight/js-component/node_modules

# Build OpenMS and pyOpenMS.
FROM setup-build-system AS compile-openms
WORKDIR /
Expand All @@ -99,6 +114,11 @@ RUN pip install dist/*.whl
# Install other dependencies (excluding pyopenms)
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^pyopenms([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
# OpenMS-Insight: install from the migration branch built in the insight-build stage
# (with its Vue bundle). The template's viewer page (visualization_template.py) imports
# it; installing from source means no PyPI publish is required.
COPY --from=insight-build /openms-insight /tmp/openms-insight
RUN pip install /tmp/openms-insight && rm -rf /tmp/openms-insight
RUN pip install -r requirements.txt

WORKDIR /
Expand Down
20 changes: 20 additions & 0 deletions Dockerfile.arm
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@ RUN mkdir /thirdparty && \
chmod -R +x /thirdparty
ENV PATH="/thirdparty/LuciPHOr2:/thirdparty/MSGFPlus:/thirdparty/ThermoRawFileParser:/thirdparty/Comet:/thirdparty/Percolator:/thirdparty/Sage:${PATH}"

# Build the OpenMS-Insight package (Python + Vue bundle) from the migration branch.
# Insight's Vue dist is gitignored and it has no pip build hook, so build the bundle
# here and sync it into the package tree; the compile-openms stage pip-installs it.
FROM node:21 AS insight-build
ARG INSIGHT_REPO=https://github.com/t0mdavid-m/openms-insight.git
ARG INSIGHT_BRANCH=claude/kind-heisenberg-u6dVm
ADD https://api.github.com/repos/t0mdavid-m/openms-insight/git/refs/heads/${INSIGHT_BRANCH} insight-ref.json
RUN git clone -b ${INSIGHT_BRANCH} --single-branch ${INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install && npm run build
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& rm -rf /openms-insight/openms_insight/js-component/dist \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist \
&& rm -rf /openms-insight/js-component/node_modules

# Build OpenMS and pyOpenMS.
FROM setup-build-system AS compile-openms
WORKDIR /
Expand Down Expand Up @@ -127,6 +142,11 @@ RUN pip install dist/*.whl
# Install other dependencies (excluding pyopenms)
COPY requirements.txt ./requirements.txt
RUN grep -Ev '^pyopenms([=<>!~].*)?$' requirements.txt > requirements_cleaned.txt && mv requirements_cleaned.txt requirements.txt
# OpenMS-Insight: install from the migration branch built in the insight-build stage
# (with its Vue bundle). The template's viewer page (visualization_template.py) imports
# it; installing from source means no PyPI publish is required.
COPY --from=insight-build /openms-insight /tmp/openms-insight
RUN pip install /tmp/openms-insight && rm -rf /tmp/openms-insight
RUN pip install -r requirements.txt

WORKDIR /
Expand Down
19 changes: 19 additions & 0 deletions Dockerfile_simple
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
# debug container after build (comment out ENTRYPOINT) and run container with interactive /bin/bash shell
# prune unused images/etc. to free disc space (e.g. might be needed on gitpod). Use with care.: docker system prune --all --force

# Build the OpenMS-Insight package (Python + Vue bundle) from the migration branch.
# Insight's Vue dist is gitignored and it has no pip build hook, so build the bundle
# here and sync it into the package tree; stage1 pip-installs it.
FROM node:21 AS insight-build
ARG INSIGHT_REPO=https://github.com/t0mdavid-m/openms-insight.git
ARG INSIGHT_BRANCH=claude/kind-heisenberg-u6dVm
ADD https://api.github.com/repos/t0mdavid-m/openms-insight/git/refs/heads/${INSIGHT_BRANCH} insight-ref.json
RUN git clone -b ${INSIGHT_BRANCH} --single-branch ${INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install && npm run build
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& rm -rf /openms-insight/openms_insight/js-component/dist \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist \
&& rm -rf /openms-insight/js-component/node_modules

FROM ubuntu:22.04 AS stage1
ARG OPENMS_REPO=https://github.com/OpenMS/OpenMS.git
ARG OPENMS_BRANCH=develop
Expand Down Expand Up @@ -60,6 +75,10 @@ SHELL ["mamba", "run", "-n", "streamlit-env", "/bin/bash", "-c"]
COPY requirements.txt requirements.txt
RUN mamba install pip
RUN python -m pip install --upgrade pip
# OpenMS-Insight: install from the migration branch built in the insight-build stage
# (with its Vue bundle); installing from source means no PyPI publish is required.
COPY --from=insight-build /openms-insight /tmp/openms-insight
RUN python -m pip install /tmp/openms-insight && rm -rf /tmp/openms-insight
RUN python -m pip install -r requirements.txt

# Pre-create bind-mount targets so apptainer/singularity has a real attach
Expand Down
19 changes: 19 additions & 0 deletions Dockerfile_simple.arm
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,21 @@
# debug container after build (comment out ENTRYPOINT) and run container with interactive /bin/bash shell
# prune unused images/etc. to free disc space (e.g. might be needed on gitpod). Use with care.: docker system prune --all --force

# Build the OpenMS-Insight package (Python + Vue bundle) from the migration branch.
# Insight's Vue dist is gitignored and it has no pip build hook, so build the bundle
# here and sync it into the package tree; stage1 pip-installs it.
FROM node:21 AS insight-build
ARG INSIGHT_REPO=https://github.com/t0mdavid-m/openms-insight.git
ARG INSIGHT_BRANCH=claude/kind-heisenberg-u6dVm
ADD https://api.github.com/repos/t0mdavid-m/openms-insight/git/refs/heads/${INSIGHT_BRANCH} insight-ref.json
RUN git clone -b ${INSIGHT_BRANCH} --single-branch ${INSIGHT_REPO} /openms-insight
WORKDIR /openms-insight/js-component
RUN npm install && npm run build
RUN mkdir -p /openms-insight/openms_insight/js-component \
&& rm -rf /openms-insight/openms_insight/js-component/dist \
&& cp -r /openms-insight/js-component/dist /openms-insight/openms_insight/js-component/dist \
&& rm -rf /openms-insight/js-component/node_modules

FROM ubuntu:22.04 AS stage1
ARG OPENMS_REPO=https://github.com/OpenMS/OpenMS.git
ARG OPENMS_BRANCH=develop
Expand Down Expand Up @@ -60,6 +75,10 @@ SHELL ["mamba", "run", "-n", "streamlit-env", "/bin/bash", "-c"]
COPY requirements.txt requirements.txt
RUN mamba install pip
RUN python -m pip install --upgrade pip
# OpenMS-Insight: install from the migration branch built in the insight-build stage
# (with its Vue bundle); installing from source means no PyPI publish is required.
COPY --from=insight-build /openms-insight /tmp/openms-insight
RUN python -m pip install /tmp/openms-insight && rm -rf /tmp/openms-insight
RUN python -m pip install -r requirements.txt

# Pre-create bind-mount targets so apptainer/singularity has a real attach
Expand Down
4 changes: 4 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
st.Page(Path("content", "run_example_workflow.py"), title="Run Workflow", icon="⚙️"),
st.Page(Path("content", "download_section.py"), title="Download Results", icon="⬇️"),
],
"Visualization Template": [
st.Page(Path("content", "visualization_template.py"),
title="Linked Grid Demo", icon="🔗"),
],
"Others Topics": [
st.Page(Path("content", "simple_workflow.py"), title="Simple Workflow", icon="⚙️"),
st.Page(Path("content", "run_subprocess.py"), title="Run Subprocess", icon="🖥️"),
Expand Down
111 changes: 111 additions & 0 deletions content/visualization_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
"""Linked Grid Demo — a self-contained showcase of the reusable OpenMS-Insight grid.

Exercises the full visualization stack on small example parquet under
``example-data/insight/``: a ``Table <-> LinePlot <-> Heatmap <-> SequenceView`` linked grid,
the :class:`~src.view.grid.LayoutManager` (edit/save/upload the layout), and the
multi-experiment + side-by-side wrapping owned by
:func:`~src.common.common.show_linked_grid`.

The four panels cross-link through one shared StateManager per experiment:
- click a row in the Spectrum table -> sets ``spectrum`` (= ``scan_id``)
- the Spectrum plot, Peak map and Sequence view all filter by ``spectrum``
- clicking a peak (in the plot / heatmap / sequence view) sets ``peak`` (= ``peak_id``)
"""

from pathlib import Path

import streamlit as st

from src.common.common import page_setup, save_params, show_linked_grid
from src.workflow.FileManager import FileManager
from src.view.grid import LayoutManager
from openms_insight import Table, LinePlot, Heatmap, SequenceView

params = page_setup()

st.title("🔗 Linked Grid Demo")
st.markdown(
"A demo of the reusable OpenMS-Insight linked grid built on the streamlit-template "
"`src/view/grid.py` module. Click a row in the **Spectrum table** to drive the linked "
"**Spectrum plot**, **Peak map** and **Sequence view**; click a peak to cross-highlight it."
)

# Example fixtures shipped with the template.
DATA = Path("example-data", "insight")

# Per-workspace results store + a dedicated Insight cache dir inside the workspace.
fm = FileManager(
st.session_state.workspace, cache_path=Path(st.session_state.workspace, "cache")
)
cache = str(Path(st.session_state.workspace, "cache", "insight"))

# Component vocabulary for the LayoutManager (human label <-> internal name).
OPTIONS = ["Spectrum table", "Spectrum plot", "Peak map", "Sequence view"]
NAMES = ["spectra_table", "spectrum_plot", "peak_map", "sequence_view"]


def builders():
"""Return the comp_name -> () -> BaseComponent factory map for one experiment."""
return {
"spectra_table": lambda: Table(
cache_id="demo_spectra",
data_path=str(DATA / "spectra.parquet"),
cache_path=cache,
interactivity={"spectrum": "scan_id"},
index_field="scan_id",
default_row=0,
title="Spectrum Table",
),
"spectrum_plot": lambda: LinePlot(
cache_id="demo_spectrum_plot",
data_path=str(DATA / "peaks.parquet"),
cache_path=cache,
filters={"spectrum": "scan_id"},
interactivity={"peak": "peak_id"},
x_column="mass",
y_column="intensity",
highlight_column="is_annotated",
annotation_column="ion_label",
title="MS/MS Spectrum",
),
"peak_map": lambda: Heatmap(
cache_id="demo_peak_map",
data_path=str(DATA / "heat.parquet"),
cache_path=cache,
x_column="rt",
y_column="mass",
intensity_column="intensity",
interactivity={"spectrum": "scan_id", "peak": "peak_id"},
title="Peak Map",
),
"sequence_view": lambda: SequenceView(
cache_id="demo_seq",
sequence_data_path=str(DATA / "sequences.parquet"),
peaks_data_path=str(DATA / "peaks.parquet"),
cache_path=cache,
filters={"spectrum": "scan_id"},
interactivity={"peak": "peak_id"},
deconvolved=True,
title="Fragment Coverage",
),
}


# Default layout used when nothing is saved (one experiment, 2x2 grid).
DEFAULT_LAYOUT = [["spectra_table", "spectrum_plot"], ["peak_map", "sequence_view"]]

tab_view, tab_layout = st.tabs(["Viewer", "Layout Manager"])

lm = LayoutManager(
OPTIONS, NAMES, store=fm, layout_id="demo_layout", session_prefix="demo"
)

with tab_layout:
lm.render()

with tab_view:
saved = lm.get_layout()
layout, side_by_side = saved if saved else ([DEFAULT_LAYOUT], False)
show_linked_grid(layout, builders(), tool="demo", side_by_side=side_by_side)

save_params(params)
Loading
Loading