dosemetrics / src /dosemetrics_app /tabs /variations.py
AKA Math
Deploy dosemetrics app - 2025-11-19 22:25:47
873a11f
Raw
History Blame Contribute Delete
5.53 kB
import streamlit as st
import plotly.express as px
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from dosemetrics.data import read_byte_data, read_dose, read_masks
from dosemetrics.metrics import dvh_by_structure, dvh_by_dose, dose_summary
from dosemetrics.utils import (
get_default_constraints,
get_custom_constraints,
compute_mirage_compliance,
)
def display_summary(doses, structure_mask):
df = dvh_by_structure(doses, structure_mask)
fig = px.line(df, x="Dose", y="Volume", color="Structure")
fig.update_xaxes(showgrid=True)
fig.update_yaxes(showgrid=True)
st.plotly_chart(fig, use_container_width=True)
summary_df = dose_summary(doses, structure_mask)
st.table(summary_df)
return summary_df
def compare_differences(summary_df, selected_structures, ref_id):
diff_table = pd.DataFrame()
st.markdown(f"#### Dose differences between Dose: {id} vs Reference: {ref_id}")
for structure in selected_structures:
diff_table.loc[:, structure] = (
summary_df[id].loc[structure, :] - summary_df[ref_id].loc[structure, :]
)
st.table(diff_table)
def display_difference_dvh(doses, structure_mask, selected_structures, ref_id):
for structure in selected_structures:
st.markdown(f"#### DVH comparisons for {structure}")
df = dvh_by_dose(doses, structure_mask[structure], structure)
fig = px.line(df, x="Dose", y="Volume", color="Structure")
fig.update_xaxes(showgrid=True)
fig.update_yaxes(showgrid=True)
st.plotly_chart(fig, use_container_width=True)
def generate_dvh_family(
dose_volume, structure_masks, constraints: pd.DataFrame, structure_of_interest: str
):
structure_mask = structure_masks[structure_of_interest]
constraint_limit = constraints.loc[structure_of_interest, "Level"]
# Generate DVH for the structure of interest
df = dvh_by_structure(dose_volume, {structure_of_interest: structure_mask})
# Create a simple plot
fig, ax = plt.subplots()
ax.plot(df["Dose"], df["Volume"])
ax.set_xlabel("Dose (Gy)")
ax.set_ylabel("Volume (%)")
ax.set_title(f"DVH for {structure_of_interest}")
ax.grid(True)
st.pyplot(fig, clear_figure=True)
st.markdown(f"Constraint limit: {constraint_limit}")
def panel():
step_1_complete = False
step_2_complete = False
step_3_complete = False
structure_mask = {}
tab1, tab2, tab3, tab4 = st.tabs(
[
"🗃️Upload Data",
"📊 View Dose Metrics",
"🔍 Compute Compliance",
"✅Evaluate Contour",
]
)
with tab1:
st.markdown(f"## Step 1: Upload dose distribution volume and mask files")
st.markdown("Upload the dose volume:")
dose_file = st.file_uploader(
f"Upload dose volume: (in .nii.gz)", type=["nii", "gz"], key=0
)
st.markdown("Upload the contour masks:")
mask_files = st.file_uploader(
"Upload mask volumes (in .nii.gz)",
accept_multiple_files=True,
type=["nii", "gz"],
key=1,
)
files_uploaded = (dose_file is not None) and (len(mask_files) > 0)
if files_uploaded:
st.markdown(
f"Both dose and mask files are uploaded. Click the toggle button below to proceed."
)
step_1_complete = st.toggle("Compute")
dose, _ = read_dose(dose_file)
structure_mask = read_masks(mask_files)
st.divider()
with tab2:
st.markdown(f"## Step 2: Dose Metrics")
st.markdown(f"Complete Step 1 to view metrics.")
if step_1_complete:
st.markdown(f"Dose Metrics: contours, dose distribution.")
dose_summary_df = display_summary(dose, structure_mask)
csv = dose_summary_df.to_csv(index=False)
st.download_button(
label="Download CSV",
data=csv,
file_name=f"dose_summary_df.csv",
mime="text/csv",
key=999,
)
st.divider()
step_2_complete = True
with tab3:
st.markdown(f"## Step 3: Display Compliance")
st.markdown(f"Complete Step 2 to proceed.")
if step_2_complete:
st.markdown(f"Clinical Compliance: contours, dose distribution.")
compliance_results = compute_mirage_compliance(dose, structure_mask)
st.table(compliance_results)
compliance_csv = compliance_results.to_csv(index=True)
st.download_button(
label="Download compliance CSV",
data=compliance_csv,
file_name="compliance.csv",
mime="text/csv",
key=500,
)
st.divider()
step_3_complete = True
with tab4:
st.markdown(f"## Step 4: Check Contour Error Impact")
st.markdown(f"Complete Step 3 to proceed.")
if step_3_complete:
st.markdown(f"Contour quality check: dice versus dose distribution.")
constraints = get_custom_constraints()
option = st.pills(
"Choose structure:",
tuple(structure_mask.keys()),
selection_mode="single",
)
st.divider()
if option is not None:
generate_dvh_family(dose, structure_mask, constraints, option)