|
|
|
|
|
import streamlit as st |
|
import pandas as pd |
|
import plotly.graph_objs as go |
|
|
|
|
|
REGRESSION_CONSTANTS = { |
|
'Femoral Neck': { |
|
'Female': {'mu': 0.916852, 'sigma': 0.120754}, |
|
'Male': {'mu': 0.9687385325352573, 'sigma': 0.121870698023835} |
|
}, |
|
'Total Hip': { |
|
'Female': {'mu': 0.955439, 'sigma': 0.125406}, |
|
'Male': {'mu': 0.967924895046735, 'sigma': 0.13081439619361657} |
|
}, |
|
'Lumbar spine (L1-L4)': { |
|
'Female': {'mu': 1.131649, 'sigma': 0.139618}, |
|
'Male': {'mu': 1.1309707991669353, 'sigma': 0.1201836924980611} |
|
} |
|
} |
|
|
|
|
|
@st.cache_data |
|
def load_medication_data(): |
|
file_path = "cleaned_bmd_medication_data.xlsx" |
|
return pd.read_excel(file_path) |
|
|
|
|
|
def calculate_bmd(bmd, percentage_increase): |
|
return bmd * (1 + percentage_increase) |
|
|
|
|
|
def calculate_tscore(bmd, mu, sigma): |
|
return (bmd - mu) / sigma |
|
|
|
|
|
def generate_predictions(medication_data, site, bmd, mu, sigma): |
|
site_data = medication_data[medication_data['Site'] == site] |
|
all_results = [] |
|
|
|
for _, row in site_data.iterrows(): |
|
drug = row['Medication'] |
|
predictions = { |
|
'Year': ['0'], |
|
'Year Index': [0], |
|
'Predicted BMD': [round(bmd, 3)], |
|
'Predicted T-score': [round(calculate_tscore(bmd, mu, sigma), 1)] |
|
} |
|
|
|
year_index = 1 |
|
for year in row.index[1:-1]: |
|
if not pd.isna(row[year]): |
|
percentage_increase = row[year] |
|
predicted_bmd = bmd * (1 + percentage_increase) |
|
predicted_tscore = calculate_tscore(predicted_bmd, mu, sigma) |
|
|
|
predictions['Year'].append(year.replace(" Year", "")) |
|
predictions['Year Index'].append(year_index) |
|
predictions['Predicted BMD'].append(round(predicted_bmd, 3)) |
|
predictions['Predicted T-score'].append(round(predicted_tscore, 1)) |
|
year_index += 1 |
|
|
|
all_results.append({'Drug': drug, 'Predictions': predictions}) |
|
return all_results |
|
|
|
|
|
|
|
def display_results(predictions, site): |
|
st.subheader(f"Predictions for {site}") |
|
|
|
for result in predictions: |
|
drug = result['Drug'] |
|
predictions = result['Predictions'] |
|
|
|
|
|
st.write(f"### {drug}") |
|
st.dataframe(pd.DataFrame(predictions)) |
|
|
|
|
|
bmd_plot = go.Scatter( |
|
x=predictions['Year Index'], y=predictions['Predicted BMD'], mode='lines+markers', |
|
name='Predicted BMD', line=dict(color='blue') |
|
) |
|
tscore_plot = go.Scatter( |
|
x=predictions['Year Index'], y=predictions['Predicted T-score'], mode='lines+markers', |
|
name='Predicted T-score', line=dict(color='green') |
|
) |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
with col1: |
|
st.plotly_chart(go.Figure(data=[bmd_plot], layout=go.Layout( |
|
title=f"{drug} - Predicted BMD", xaxis_title="Year", yaxis_title="BMD (g/cm²)", |
|
xaxis=dict(tickmode='array', tickvals=predictions['Year Index'], ticktext=predictions['Year']) |
|
))) |
|
with col2: |
|
st.plotly_chart(go.Figure(data=[tscore_plot], layout=go.Layout( |
|
title=f"{drug} - Predicted T-score", xaxis_title="Year", yaxis_title="T-score", |
|
xaxis=dict(tickmode='array', tickvals=predictions['Year Index'], ticktext=predictions['Year']) |
|
))) |
|
|
|
|
|
def generate_goal_summary(predictions, target_tscore=-2.4): |
|
def year_to_int(year): |
|
|
|
try: |
|
return int(year.rstrip("stndrdth")) |
|
except ValueError: |
|
return 0 |
|
|
|
goal_reached = [] |
|
|
|
for result in predictions: |
|
drug = result['Drug'] |
|
predictions_data = result['Predictions'] |
|
|
|
for year, tscore in zip(predictions_data['Year'], predictions_data['Predicted T-score']): |
|
if tscore >= target_tscore: |
|
|
|
numeric_year = year_to_int(year) |
|
goal_reached.append({'Medication': drug, 'Year': numeric_year}) |
|
break |
|
|
|
|
|
goal_reached_sorted = sorted(goal_reached, key=lambda x: x['Year']) |
|
return goal_reached_sorted |
|
|
|
|
|
def display_goal_summary(goal_summary): |
|
st.subheader("Goal Treatment Summary (T-score ≥ -2.4)") |
|
|
|
if not goal_summary: |
|
st.info("No medications reach the target T-score.") |
|
else: |
|
summary_table = pd.DataFrame(goal_summary) |
|
st.table(summary_table) |
|
|
|
|
|
def select_medications(): |
|
st.subheader("Select Medications to Display") |
|
show_all = st.checkbox("Show All Medications", key="show_all") |
|
|
|
selected_medications = [] |
|
if not show_all: |
|
|
|
categories = { |
|
"Bisphosphonates": [ |
|
"Alendronate", "Risedronate", "Ibandronate oral", |
|
"Zoledronate", "Ibandronate IV (3mg)" |
|
], |
|
"RANK Ligand Inhibitors": [ |
|
"Denosumab", "Denosumab + Teriparatide" |
|
], |
|
"Anabolic Agents": [ |
|
"Teriparatide", "Teriparatide + Denosumab" |
|
], |
|
"Sclerostin Inhibitors": [ |
|
"Romosozumab", "Romosozumab + Denosumab", |
|
"Romosozumab + Alendronate", "Romosozumab + Ibandronate", |
|
"Romosozumab + Zoledronate" |
|
] |
|
} |
|
|
|
|
|
for category, medications in categories.items(): |
|
with st.expander(category): |
|
for med in medications: |
|
|
|
if st.checkbox(med, key=f"{category}_{med}"): |
|
selected_medications.append(med) |
|
else: |
|
|
|
selected_medications = [ |
|
"Alendronate", "Risedronate", "Ibandronate oral", |
|
"Zoledronate", "Ibandronate IV (3mg)", "Denosumab", |
|
"Denosumab + Teriparatide", "Teriparatide", |
|
"Teriparatide + Denosumab", "Romosozumab", |
|
"Romosozumab + Denosumab", "Romosozumab + Alendronate", |
|
"Romosozumab + Ibandronate", "Romosozumab + Zoledronate" |
|
] |
|
|
|
return selected_medications |
|
|
|
|
|
|
|
def main(): |
|
st.title("BMD and T-score Prediction Tool") |
|
|
|
|
|
dexa_machine = st.selectbox("DEXA Machine", ["LUNAR"]) |
|
|
|
|
|
gender = st.selectbox("Gender", ["Female", "Male"]) |
|
|
|
|
|
site_mapping = { |
|
'Lumbar spine (L1-L4)': 'LS', |
|
'Femoral Neck': 'FN', |
|
'Total Hip': 'TH' |
|
} |
|
site_options = list(site_mapping.keys()) |
|
selected_site = st.selectbox("Select Region (Site)", site_options) |
|
site = site_mapping[selected_site] |
|
|
|
|
|
bmd_patient = st.number_input( |
|
"Initial BMD", |
|
min_value=0.000, max_value=2.000, |
|
value=0.800, step=0.001, |
|
format="%.3f" |
|
) |
|
|
|
|
|
selected_medications = select_medications() |
|
|
|
|
|
medication_data = load_medication_data() |
|
constants = REGRESSION_CONSTANTS[selected_site][gender] |
|
|
|
|
|
if st.button("Predict"): |
|
all_predictions = generate_predictions(medication_data, site, bmd_patient, constants['mu'], constants['sigma']) |
|
filtered_predictions = [pred for pred in all_predictions if pred['Drug'] in selected_medications] |
|
|
|
if not filtered_predictions: |
|
st.warning("No medications selected. Please select at least one medication or use the 'Show All' option.") |
|
else: |
|
|
|
goal_summary = generate_goal_summary(filtered_predictions, target_tscore=-2.4) |
|
display_goal_summary(goal_summary) |
|
|
|
|
|
display_results(filtered_predictions, selected_site) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
|
|