Skip to content
Open
Changes from 3 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
118 changes: 112 additions & 6 deletions src/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pyopenms as poms
from src.common.common import show_fig, display_large_dataframe
from typing import Union
from plotly.subplots import make_subplots


def get_df(file: Union[str, Path]) -> pd.DataFrame:
Expand Down Expand Up @@ -170,6 +171,8 @@ def plot_ms_spectrum(df, title, bin_peaks, num_x_bins):
@st.fragment
def view_peak_map():
df = st.session_state.view_ms1

#Apply Box Selection Filtering
if "view_peak_map_selection" in st.session_state:
box = st.session_state.view_peak_map_selection.selection.box
if box:
Expand All @@ -178,29 +181,99 @@ def view_peak_map():
df = df[df["mz"] > box[0]["y"][1]]
df = df[df["mz"] < box[0]["y"][0]]
df = df[df["RT"] < box[0]["x"][1]]

peak_map = df.plot(
kind="peakmap",
x="RT",
y="mz",
z="inty",
title=st.session_state.view_selected_file,
xlabel="Retention Time (s)",
ylabel="m/z",
grid=False,
show_plot=False,
bin_peaks=True,
backend="ms_plotly",
aggregate_duplicates=True,
)
peak_map.update_layout(template="simple_white", dragmode="select")

df_tic = df.groupby("RT").sum().reset_index()

marginal_tic = go.Figure()
marginal_tic.add_trace(
go.Scatter(
x=df_tic["RT"],
y=df_tic["inty"],
mode="lines",
line=dict(color="#f24c5c", width=2),
name="TIC",
)
)

marginal_tic.update_layout(
height=200,
margin=dict(l=0, r=0, t=0, b=0),
plot_bgcolor="rgb(255,255,255)",
xaxis=dict(title="Retention Time (s)"),
yaxis=dict(title="TIC")
)

combined_fig = make_subplots(
rows=2,
cols=1,
shared_xaxes=True,
row_heights=[0.7, 0.3], # Peak map gets 70%, TIC gets 30%
vertical_spacing=0.05
)

for trace in peak_map.data:
combined_fig.add_trace(trace, row=1, col=1)

for trace in marginal_tic.data:
combined_fig.add_trace(trace, row=2, col=1)

combined_fig.update_layout(
template="simple_white",
dragmode="zoom",

xaxis=dict(
showgrid=False,
domain=[0, 1]
),

xaxis2=dict(
title="Retention Time (s)",
rangeslider=dict(visible=True),
showgrid=False
),

yaxis=dict(title="m/z"), # Y-axis for peak map
yaxis2=dict(title="TIC"), # Y-axis for TIC

height=850,
margin=dict(t=100, b=100),
title=dict(
text=st.session_state.view_selected_file,
x=0.5,
y=0.99,
xanchor="center",
yanchor="top",
font=dict(size=18, family="Arial, sans-serif")
)
)
Comment on lines +245 to +261
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Combined figure layout could be improved.

While the layout configuration is generally good, there's an issue with the minallowed and maxallowed properties:

-        xaxis=dict(title="Retention Time (s)", showgrid=False, minallowed="0", maxallowed="1000"),
+        xaxis=dict(title="Retention Time (s)", showgrid=False, range=[0, 1000]),

The minallowed and maxallowed properties define input constraints but don't limit the visible range. The range property would better ensure the visualization starts with the desired range. Also, the values are passed as strings instead of numbers, which is inconsistent with Plotly conventions.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
combined_fig.update_layout(
template="simple_white",
dragmode="zoom",
xaxis=dict(title="Retention Time (s)", showgrid=False, minallowed="0", maxallowed="1000"),
yaxis=dict(title="m/z", fixedrange=True),
yaxis2=dict(title="TIC", autorange="reversed", fixedrange=True),
height=850,
margin=dict(t=100, b=100),
title=dict(
text=st.session_state.view_selected_file,
x=0.5,
y=0.99,
xanchor="center",
yanchor="top",
font=dict(size=18, family="Arial, sans-serif")
)
)
combined_fig.update_layout(
template="simple_white",
dragmode="zoom",
- xaxis=dict(title="Retention Time (s)", showgrid=False, minallowed="0", maxallowed="1000"),
+ xaxis=dict(title="Retention Time (s)", showgrid=False, range=[0, 1000]),
yaxis=dict(title="m/z", fixedrange=True),
yaxis2=dict(title="TIC", autorange="reversed", fixedrange=True),
height=850,
margin=dict(t=100, b=100),
title=dict(
text=st.session_state.view_selected_file,
x=0.5,
y=0.99,
xanchor="center",
yanchor="top",
font=dict(size=18, family="Arial, sans-serif")
)
)


c1, c2 = st.columns(2)

with c1:
st.info(
"💡 Zoom in via rectangular selection for more details and 3D plot. Double click plot to zoom back out."
"💡 Zoom in via rectangular selection for more details and 3D plot. "
"Double click plot to zoom back out."
)
show_fig(
peak_map,
combined_fig,
f"peak_map_{st.session_state.view_selected_file}",
selection_session_state_key="view_peak_map_selection",
)

with c2:
if df.shape[0] < 2500:
peak_map_3D = df.plot(
Expand All @@ -211,6 +284,8 @@ def view_peak_map():
y="mz",
z="inty",
zlabel="Intensity",
xlabel="Retention Time (s)",
ylabel="m/z",
title="",
show_plot=False,
grid=False,
Expand All @@ -220,9 +295,17 @@ def view_peak_map():
width=900,
aggregate_duplicates=True,
)
st.plotly_chart(peak_map_3D, use_container_width=True)

peak_map_3D.update_layout(
scene=dict(
xaxis=dict(title="Retention Time (s)"),
yaxis=dict(title="m/z"),
zaxis=dict(title="Intensity"),
dragmode="orbit"
)
)
Comment on lines +297 to +304
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

3D peak map layout alignment with 2D plot.

The 3D peak map layout is correctly configured to maintain consistency with the 2D visualization, however it has the same issue with minallowed and maxallowed properties:

-                    xaxis=dict(title="Retention Time (s)", minallowed="0", maxallowed="1000"),
+                    xaxis=dict(title="Retention Time (s)", range=[0, 1000]),

Setting dragmode="orbit" is a good choice for 3D visualization as it provides more intuitive navigation.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
peak_map_3D.update_layout(
scene=dict(
xaxis=dict(title="Retention Time (s)", minallowed="0", maxallowed="1000"),
yaxis=dict(title="m/z", fixedrange=True),
zaxis=dict(title="Intensity"),
dragmode="orbit"
)
)
peak_map_3D.update_layout(
scene=dict(
xaxis=dict(title="Retention Time (s)", range=[0, 1000]),
yaxis=dict(title="m/z", fixedrange=True),
zaxis=dict(title="Intensity"),
dragmode="orbit"
)
)


st.plotly_chart(peak_map_3D, use_container_width=True)
@st.fragment
def view_spectrum():
cols = st.columns([0.34, 0.66])
Expand Down Expand Up @@ -316,4 +399,27 @@ def view_bpc_tic():
key="view_eic_ppm",
)
fig = plot_bpc_tic()
show_fig(fig, f"BPC-TIC-{st.session_state.view_selected_file}")

fig.update_layout(
xaxis=dict(
rangeslider=dict(visible=True), # Range slider for x-axis zoom
rangeselector=dict( # Zoom buttons
buttons=list([
dict(count=1, label="1s", step="second", stepmode="backward"),
dict(count=10, label="10s", step="second", stepmode="backward"),
dict(count=1, label="1m", step="minute", stepmode="backward"),
dict(step="all")
])
)
),
margin=dict(l=0, r=0, t=0, b=0), # Remove margins for full-width display
height=700, # Increase height for better visualization
hovermode="x unified", # Unified hover tooltip
modebar=dict(
orientation='h', # Horizontal toolbar
bgcolor='rgba(255,255,255,0.7)', # Toolbar background color
)
)

# Display full-width chromatogram
st.plotly_chart(fig, use_container_width=True)