|
import random |
|
from datetime import timedelta, date |
|
import firebase_admin |
|
from firebase_admin import credentials, storage, firestore |
|
import streamlit as st |
|
import streamlit_authenticator as stauth |
|
import pandas as pd |
|
import plotly.express as px |
|
import plotly.graph_objects as go |
|
import json, os, dotenv |
|
from dotenv import load_dotenv |
|
load_dotenv() |
|
|
|
|
|
|
|
os.environ["FIREBASE_CREDENTIAL"] = dotenv.get_key(dotenv.find_dotenv(), "FIREBASE_CREDENTIAL") |
|
cred = credentials.Certificate(json.loads(os.environ.get("FIREBASE_CREDENTIAL"))) |
|
|
|
|
|
if not firebase_admin._apps: |
|
firebase_admin.initialize_app(cred, {'storageBucket': 'healthhack-store.appspot.com'}) |
|
|
|
|
|
db = firestore.client() |
|
|
|
docs = db.collection("clinical_scores").stream() |
|
|
|
|
|
data = [] |
|
for doc in docs: |
|
doc_dict = doc.to_dict() |
|
doc_dict['document_id'] = doc.id |
|
data.append(doc_dict) |
|
|
|
|
|
df = pd.DataFrame(data) |
|
|
|
|
|
|
|
|
|
def standardize_grade(value): |
|
if pd.isna(value): |
|
return value |
|
value = str(value).upper().strip() |
|
if value and value[0] in ['A', 'B', 'C', 'D', 'E']: |
|
return value[0] |
|
return value |
|
|
|
|
|
columns_to_check = ['hx_others_score', 'hx_AS_score', 'differentials_score', 'global_score'] |
|
|
|
|
|
df[columns_to_check] = df[columns_to_check].applymap(standardize_grade) |
|
|
|
login_info = { |
|
"student1": "password", |
|
"student2": "password", |
|
"student3": "password", |
|
"admin":"admin" |
|
} |
|
|
|
username = None |
|
|
|
def set_username(x): |
|
st.session_state.username = x |
|
|
|
def validate_username(username, password): |
|
if login_info.get(username) == password: |
|
set_username(username) |
|
else: |
|
st.warning("Wrong username or password") |
|
return None |
|
|
|
if not st.session_state.get("username"): |
|
|
|
st.title("Login") |
|
username = st.text_input("Username:") |
|
password = st.text_input("Password:", type="password") |
|
login_button = st.button("Login", on_click=validate_username, args=[username, password]) |
|
|
|
if st.session_state.get("username"): |
|
username = st.session_state.get("username") |
|
st.title(f"Hello there, {st.session_state.username}") |
|
|
|
|
|
if st.button('Logout'): |
|
|
|
del st.session_state.username |
|
|
|
st.rerun() |
|
|
|
|
|
df['date'] = pd.to_datetime(df['date'], errors='coerce') |
|
|
|
|
|
|
|
|
|
|
|
if username != 'admin': |
|
df_selection = df[df['name'] == username] |
|
else: |
|
df_selection = df |
|
|
|
|
|
st.title(":bar_chart: Student Performance Dashboard") |
|
st.markdown("##") |
|
|
|
|
|
if df_selection.empty: |
|
st.error("No data available to display.") |
|
else: |
|
|
|
total_attempts_by_name = df_selection.groupby("name")['date'].count().reset_index() |
|
total_attempts_by_name.columns = ['name', 'total_attempts'] |
|
|
|
|
|
fig_total_attempts = px.scatter( |
|
total_attempts_by_name, |
|
x="name", |
|
y="total_attempts", |
|
title="<b>Total Attempts</b>", |
|
size='total_attempts', |
|
color_discrete_sequence=["#0083B8"] * len(total_attempts_by_name), |
|
template="plotly_white", |
|
text='total_attempts' |
|
) |
|
|
|
|
|
for line in range(0, total_attempts_by_name.shape[0]): |
|
fig_total_attempts.add_annotation( |
|
text=str(total_attempts_by_name['total_attempts'].iloc[line]), |
|
x=total_attempts_by_name['name'].iloc[line], |
|
y=total_attempts_by_name['total_attempts'].iloc[line], |
|
showarrow=True, |
|
font=dict(family="Courier New, monospace", size=18, color="#ffffff"), |
|
align="center", |
|
arrowhead=2, |
|
arrowsize=1, |
|
arrowwidth=2, |
|
arrowcolor="#636363", |
|
ax=20, |
|
ay=-30, |
|
bordercolor="#c7c7c7", |
|
borderwidth=2, |
|
borderpad=4, |
|
bgcolor="#ff7f0e", |
|
opacity=0.8 |
|
) |
|
|
|
|
|
fig_total_attempts.update_traces(marker=dict(size=12), selector=dict(mode='markers+text')) |
|
|
|
|
|
st.plotly_chart(fig_total_attempts, use_container_width=True) |
|
|
|
|
|
if username != 'admin': |
|
|
|
df_selection = df_selection.sort_values(by='date') |
|
|
|
|
|
if len(df_selection) > 1: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
grade_to_score = {'A': 100, 'B': 80, 'C': 60, 'D': 40, 'E': 20} |
|
|
|
|
|
df_selection['numeric_score'] = df_selection['global_score'].map(grade_to_score) |
|
|
|
|
|
df_selection = df_selection.sort_values(by='date') |
|
|
|
|
|
if len(df_selection) > 1: |
|
|
|
fig = px.bar(df_selection, x='date', y='numeric_score', title='Your scores over time') |
|
else: |
|
|
|
fig = px.bar(df_selection, x='date', y='numeric_score', title='Global Score') |
|
|
|
|
|
fig.update_yaxes( |
|
tickmode='array', |
|
tickvals=list(grade_to_score.values()), |
|
ticktext=list(grade_to_score.keys()), |
|
range=[0, 120] |
|
) |
|
|
|
|
|
|
|
|
|
else: |
|
|
|
fig = px.scatter(df_selection, x='date', y='global_score', title='Global Score', |
|
text='global_score', size_max=60) |
|
|
|
for line in range(0,df_selection.shape[0]): |
|
fig.add_annotation(text=df_selection['global_score'].iloc[line], |
|
x=df_selection['date'].iloc[line], y=df_selection['global_score'].iloc[line], |
|
showarrow=True, font=dict(family="Courier New, monospace", size=18, color="#ffffff"), |
|
align="center", arrowhead=2, arrowsize=1, arrowwidth=2, arrowcolor="#636363", |
|
ax=20, ay=-30, bordercolor="#c7c7c7", borderwidth=2, borderpad=4, bgcolor="#ff7f0e", |
|
opacity=0.8) |
|
fig.update_traces(marker=dict(size=12), selector=dict(mode='markers+text')) |
|
|
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|
|
st.dataframe(df_selection[['date', 'global_score', 'name']]) |
|
|
|
|
|
|
|
|
|
order_of_categories = ['A', 'B', 'C', 'D', 'E'] |
|
|
|
|
|
df_selection['global_score'] = pd.Categorical(df_selection['global_score'], categories=order_of_categories, ordered=True) |
|
|
|
|
|
fig_score_distribution = px.histogram( |
|
df_selection, |
|
x="global_score", |
|
title="<b>Global Score Distribution</b>", |
|
color_discrete_sequence=["#33CFA5"], |
|
category_orders={"global_score": ["A", "B", "C", "D", "E"]} |
|
) |
|
if username == 'admin': |
|
st.plotly_chart(fig_score_distribution, use_container_width=True) |
|
|
|
|
|
|
|
if username == 'admin': |
|
students_with_less_than_5_attempts = total_attempts_by_name[total_attempts_by_name['total_attempts'] < 5] |
|
fig_less_than_5_attempts = px.bar( |
|
students_with_less_than_5_attempts, |
|
x="name", |
|
y="total_attempts", |
|
title="<b>Students with <5 Attempts</b>", |
|
color_discrete_sequence=["#D62728"] * len(students_with_less_than_5_attempts), |
|
template="plotly_white", |
|
) |
|
|
|
if username == 'admin': |
|
st.plotly_chart(fig_less_than_5_attempts, use_container_width=True) |
|
|
|
|
|
|
|
if username == 'admin': |
|
selected_student_less_than_5 = st.selectbox("Select a student with less than 5 attempts to view details:", students_with_less_than_5_attempts['name']) |
|
if selected_student_less_than_5: |
|
st.write(df_selection[df_selection['name'] == selected_student_less_than_5]) |
|
|
|
|
|
if username == 'admin': |
|
students_with_cde = df_selection[df_selection['global_score'].isin(['C', 'D', 'E'])].groupby("name")['date'].count().reset_index() |
|
students_with_cde.columns = ['name', 'total_attempts'] |
|
fig_students_with_cde = px.bar( |
|
students_with_cde, |
|
x="name", |
|
y="total_attempts", |
|
title="<b>Students with at least one global score of 'C', 'D', 'E'</b>", |
|
color_discrete_sequence=["#FF7F0E"] * len(students_with_cde), |
|
template="plotly_white", |
|
) |
|
st.plotly_chart(fig_students_with_cde, use_container_width=True) |
|
|
|
|
|
if username == 'admin': |
|
selected_student_cde = st.selectbox("Select a student with at least one score of 'C', 'D', 'E' to view details:", students_with_cde['name']) |
|
if selected_student_cde: |
|
st.write(df_selection[df_selection['name'] == selected_student_cde]) |
|
|
|
|
|
|
|
|
|
grade_to_numeric = {'A': 90, 'B': 70, 'C': 50, 'D': 30, 'E': 10} |
|
df.replace(grade_to_numeric, inplace=True) |
|
|
|
|
|
average_scores = df.groupby('name')[['hx_PC_score', 'hx_AS_score', 'hx_others_score', 'differentials_score']].mean().reset_index() |
|
|
|
if username == 'admin': |
|
st.title('Average Scores Radar Chart') |
|
else: |
|
st.title('Performance in each segment as compared to your friends!') |
|
|
|
|
|
categories = ['Presenting complaint', 'Associated symptoms', '(Others)', 'Differentials'] |
|
|
|
st.markdown(""" |
|
### |
|
Double click on the names in the legend to include/exclude them from the plot. |
|
""") |
|
|
|
|
|
|
|
colors = ['gold', 'cyan', 'magenta', 'green'] |
|
|
|
|
|
fig = go.Figure() |
|
|
|
for index, row in average_scores.iterrows(): |
|
fig.add_trace(go.Scatterpolar( |
|
r=[row['hx_PC_score'], row['hx_AS_score'], row['hx_others_score'], row['differentials_score']], |
|
theta=categories, |
|
fill='toself', |
|
name=row['name'], |
|
line=dict(color=colors[index % len(colors)]) |
|
)) |
|
|
|
fig.update_layout( |
|
polar=dict( |
|
radialaxis=dict( |
|
visible=True, |
|
range=[0, 100], |
|
tickvals=[10, 30, 50, 70, 90], |
|
ticktext=['E', 'D', 'C', 'B', 'A'] |
|
)), |
|
showlegend=True, |
|
height=600, |
|
width=600 |
|
) |
|
|
|
|
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
|