import streamlit as st import pandas as pd import plotly.express as px import plotly.graph_objects as go from plotly.subplots import make_subplots import numpy as np # Set page config st.set_page_config( page_title="Health Parameter Transition Dashboard", page_icon="🏥", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for better styling st.markdown(""" """, unsafe_allow_html=True) @st.cache_data def load_data(): """Load and preprocess the health data""" try: df = pd.read_csv("Combines 2,3,7,9,11(Sheet1).csv") return df except Exception as e: st.error(f"Error loading data: {e}") return None def clean_tag_data(df): """Clean and standardize tag data""" # Define health parameters with their old and new tag columns health_params = { 'HbA1c': {'old_tag': 'Hba1c tag old', 'new_tag': 'Hba1c tag'}, 'LDL': {'old_tag': 'LDLtag old', 'new_tag': 'LDLtag'}, 'BMI': {'old_tag': 'BMItag old', 'new_tag': 'BMItag'}, 'BP': {'old_tag': 'Bptag old', 'new_tag': 'Bptag'}, 'Biometrics': {'old_tag': 'biometric tag old', 'new_tag': 'biometric tag'}, 'MHI': {'old_tag': 'MHI old', 'new_tag': 'MHI NEW'} } # Clean the data for param, cols in health_params.items(): # Fill NaN values with 'Not Available' df[cols['old_tag']] = df[cols['old_tag']].fillna('Not Available') df[cols['new_tag']] = df[cols['new_tag']].fillna('Not Available') # Standardize tag values for col in [cols['old_tag'], cols['new_tag']]: df[col] = df[col].astype(str).str.strip().str.title() # Map common variations df[col] = df[col].replace({ 'Alert': 'Red', 'Sub-Optimal': 'Orange', 'Optimal': 'Green', 'Suboptimal': 'Orange', '0': 'Not Available', '': 'Not Available' }) return df, health_params def calculate_transitions(df, health_params, location_filter=None): """Calculate transition matrices for each health parameter""" if location_filter and location_filter != "All Locations": df_filtered = df[df['Location Shared'] == location_filter].copy() else: df_filtered = df.copy() transitions = {} for param, cols in health_params.items(): old_col = cols['old_tag'] new_col = cols['new_tag'] # Create transition matrix transition_df = df_filtered[[old_col, new_col]].copy() transition_df = transition_df[ (transition_df[old_col] != 'Not Available') & (transition_df[new_col] != 'Not Available') ] if len(transition_df) > 0: transition_matrix = pd.crosstab( transition_df[old_col], transition_df[new_col], margins=True ) # Calculate transition summary total_users = len(transition_df) # Count improvements, declines, and stable improved = 0 declined = 0 stable = 0 tag_hierarchy = {'Red': 3, 'Orange': 2, 'Green': 1} for _, row in transition_df.iterrows(): old_val = row[old_col] new_val = row[new_col] if old_val in tag_hierarchy and new_val in tag_hierarchy: old_score = tag_hierarchy[old_val] new_score = tag_hierarchy[new_val] if new_score < old_score: # Lower score is better improved += 1 elif new_score > old_score: declined += 1 else: stable += 1 transitions[param] = { 'matrix': transition_matrix, 'total_users': total_users, 'improved': improved, 'declined': declined, 'stable': stable, 'improvement_rate': (improved / total_users * 100) if total_users > 0 else 0, 'decline_rate': (declined / total_users * 100) if total_users > 0 else 0, 'stable_rate': (stable / total_users * 100) if total_users > 0 else 0 } return transitions def create_transition_heatmap(transition_matrix, param_name): """Create a heatmap for transition matrix""" # Remove the 'All' row and column for cleaner visualization matrix_clean = transition_matrix.drop('All', axis=0).drop('All', axis=1) fig = px.imshow( matrix_clean.values, x=matrix_clean.columns, y=matrix_clean.index, color_continuous_scale='Blues', aspect="auto", title=f"{param_name} Transition Matrix" ) # Add text annotations for i, row in enumerate(matrix_clean.index): for j, col in enumerate(matrix_clean.columns): fig.add_annotation( x=j, y=i, text=str(matrix_clean.loc[row, col]), showarrow=False, font=dict(color="white" if matrix_clean.loc[row, col] > matrix_clean.values.max()/2 else "black") ) fig.update_layout( xaxis_title="New Status", yaxis_title="Old Status", height=400 ) return fig def create_summary_chart(transitions): """Create summary chart showing improvement/decline rates""" params = list(transitions.keys()) improvement_rates = [transitions[p]['improvement_rate'] for p in params] decline_rates = [transitions[p]['decline_rate'] for p in params] stable_rates = [transitions[p]['stable_rate'] for p in params] fig = go.Figure() fig.add_trace(go.Bar( name='Improved', x=params, y=improvement_rates, marker_color='#2ca02c' )) fig.add_trace(go.Bar( name='Declined', x=params, y=decline_rates, marker_color='#d62728' )) fig.add_trace(go.Bar( name='Stable', x=params, y=stable_rates, marker_color='#ff7f0e' )) fig.update_layout( title="Health Parameter Transition Summary", xaxis_title="Health Parameters", yaxis_title="Percentage of Users", barmode='stack', height=500 ) return fig def create_sankey_diagram(df, param, old_col, new_col, location_filter=None): """Create Sankey diagram for parameter transitions""" if location_filter and location_filter != "All Locations": df_filtered = df[df['Location Shared'] == location_filter].copy() else: df_filtered = df.copy() # Filter out 'Not Available' values df_filtered = df_filtered[ (df_filtered[old_col] != 'Not Available') & (df_filtered[new_col] != 'Not Available') ] if len(df_filtered) == 0: return None # Create transition counts transitions = df_filtered.groupby([old_col, new_col]).size().reset_index(name='count') # Create unique labels all_labels = list(set(transitions[old_col].tolist() + transitions[new_col].tolist())) label_map = {label: i for i, label in enumerate(all_labels)} # Prepare data for Sankey source = [label_map[old] for old in transitions[old_col]] target = [label_map[new] + len(set(transitions[old_col])) for new in transitions[new_col]] values = transitions['count'].tolist() # Create color mapping color_map = {'Green': '#2ca02c', 'Orange': '#ff7f0e', 'Red': '#d62728'} node_colors = [color_map.get(label, '#1f77b4') for label in all_labels] fig = go.Figure(data=[go.Sankey( node=dict( pad=15, thickness=20, line=dict(color="black", width=0.5), label=[f"{label} (Old)" if i < len(set(transitions[old_col])) else f"{label} (New)" for i, label in enumerate(all_labels + all_labels)], color=node_colors + node_colors ), link=dict( source=source, target=target, value=values ) )]) fig.update_layout( title_text=f"{param} Parameter Transitions", font_size=10, height=400 ) return fig def main(): st.markdown('