Spaces:
Sleeping
Sleeping
rollback last commit
Browse files
app.py
CHANGED
|
@@ -2,8 +2,7 @@ import streamlit as st
|
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
import base64, pickle, textwrap
|
| 5 |
-
import plotly.
|
| 6 |
-
from plotly.subplots import make_subplots
|
| 7 |
|
| 8 |
# ---------------------------------------------------
|
| 9 |
# Page configuration for wide layout
|
|
@@ -31,33 +30,45 @@ st.sidebar.title("Filters")
|
|
| 31 |
|
| 32 |
def_opts = sorted(df['Dept Track'].dropna().astype(str).unique())
|
| 33 |
def_stand = sorted(df['Standing'].dropna().astype(str).unique())
|
| 34 |
-
|
|
|
|
| 35 |
if st.sidebar.button("Clear All Filters"):
|
| 36 |
-
|
| 37 |
-
|
|
|
|
| 38 |
|
| 39 |
-
# Filter widgets
|
| 40 |
standing_sel = st.sidebar.multiselect(
|
| 41 |
-
"Filter by Standing:",
|
| 42 |
-
|
|
|
|
|
|
|
| 43 |
)
|
|
|
|
| 44 |
dept_sel = st.sidebar.multiselect(
|
| 45 |
-
"Filter by Dept Track:",
|
| 46 |
-
|
|
|
|
|
|
|
| 47 |
)
|
| 48 |
-
|
|
|
|
| 49 |
mask = (
|
| 50 |
-
df['Standing'].astype(str).isin(
|
| 51 |
-
df['Dept Track'].astype(str).isin(
|
| 52 |
)
|
| 53 |
name_opts = sorted(df.loc[mask, 'Name'].astype(str).unique())
|
|
|
|
|
|
|
| 54 |
if 'names' not in st.session_state or st.session_state.names is None:
|
| 55 |
st.session_state.names = name_opts.copy()
|
| 56 |
else:
|
| 57 |
st.session_state.names = [n for n in st.session_state.names if n in name_opts]
|
|
|
|
| 58 |
name_sel = st.sidebar.multiselect(
|
| 59 |
-
"Select Faculty:",
|
| 60 |
-
|
|
|
|
|
|
|
| 61 |
)
|
| 62 |
|
| 63 |
# ---------------------------------------------------
|
|
@@ -65,67 +76,42 @@ name_sel = st.sidebar.multiselect(
|
|
| 65 |
# ---------------------------------------------------
|
| 66 |
st.title("Faculty Heatmap Explorer")
|
| 67 |
|
|
|
|
| 68 |
if not name_sel:
|
| 69 |
st.warning("No faculty selected — please choose at least one.")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
else:
|
| 71 |
-
# Combine
|
| 72 |
sum_df = None
|
| 73 |
for name in name_sel:
|
| 74 |
mat = filled_matrices[name]
|
| 75 |
sum_df = mat if sum_df is None else sum_df.add(mat, fill_value=0)
|
| 76 |
avg_df = sum_df.div(len(name_sel))
|
| 77 |
|
| 78 |
-
#
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
#
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
shared_yaxes=True,
|
| 95 |
-
horizontal_spacing=0.02,
|
| 96 |
-
subplot_titles=[f"Avg Heatmap for {len(name_sel)} Faculty", "Row Sum"]
|
| 97 |
-
)
|
| 98 |
-
# Main heatmap
|
| 99 |
-
fig.add_trace(
|
| 100 |
-
go.Heatmap(
|
| 101 |
-
z=avg_df.values,
|
| 102 |
-
x=wrapped_x_main,
|
| 103 |
-
y=wrapped_y,
|
| 104 |
-
text=np.round(avg_df.values, 2),
|
| 105 |
-
texttemplate="%{text}",
|
| 106 |
-
colorscale="Blues",
|
| 107 |
-
zmin=zmin, zmax=zmax,
|
| 108 |
-
colorbar=dict(title="Avg value", x=0.45)
|
| 109 |
-
), row=1, col=1
|
| 110 |
-
)
|
| 111 |
-
# Sum column heatmap
|
| 112 |
-
fig.add_trace(
|
| 113 |
-
go.Heatmap(
|
| 114 |
-
z=row_sums.values.reshape(-1, 1),
|
| 115 |
-
x=["Sum"],
|
| 116 |
-
y=wrapped_y,
|
| 117 |
-
text=np.round(row_sums.values, 2),
|
| 118 |
-
texttemplate="%{text}",
|
| 119 |
-
colorscale="Blues",
|
| 120 |
-
zmin=zmin, zmax=zmax,
|
| 121 |
-
showscale=False
|
| 122 |
-
), row=1, col=2
|
| 123 |
-
)
|
| 124 |
-
# Update layout
|
| 125 |
-
fig.update_yaxes(autorange='reversed', ticks='', tickfont=dict(size=10))
|
| 126 |
-
fig.update_xaxes(tickangle=45)
|
| 127 |
-
fig.update_layout(
|
| 128 |
-
height=800,
|
| 129 |
-
margin=dict(l=100, r=50, t=100, b=50)
|
| 130 |
)
|
|
|
|
|
|
|
|
|
|
| 131 |
st.plotly_chart(fig, use_container_width=True)
|
|
|
|
| 2 |
import pandas as pd
|
| 3 |
import numpy as np
|
| 4 |
import base64, pickle, textwrap
|
| 5 |
+
import plotly.express as px
|
|
|
|
| 6 |
|
| 7 |
# ---------------------------------------------------
|
| 8 |
# Page configuration for wide layout
|
|
|
|
| 30 |
|
| 31 |
def_opts = sorted(df['Dept Track'].dropna().astype(str).unique())
|
| 32 |
def_stand = sorted(df['Standing'].dropna().astype(str).unique())
|
| 33 |
+
|
| 34 |
+
# Clear filters button resets session state
|
| 35 |
if st.sidebar.button("Clear All Filters"):
|
| 36 |
+
st.session_state.pop('standing', None)
|
| 37 |
+
st.session_state.pop('dept', None)
|
| 38 |
+
st.session_state.pop('names', None)
|
| 39 |
|
|
|
|
| 40 |
standing_sel = st.sidebar.multiselect(
|
| 41 |
+
"Filter by Standing:",
|
| 42 |
+
options=def_stand,
|
| 43 |
+
default=st.session_state.get('standing', def_stand),
|
| 44 |
+
key='standing'
|
| 45 |
)
|
| 46 |
+
|
| 47 |
dept_sel = st.sidebar.multiselect(
|
| 48 |
+
"Filter by Dept Track:",
|
| 49 |
+
options=def_opts,
|
| 50 |
+
default=st.session_state.get('dept', def_opts),
|
| 51 |
+
key='dept'
|
| 52 |
)
|
| 53 |
+
|
| 54 |
+
# Filter names based on selected Standing & Dept
|
| 55 |
mask = (
|
| 56 |
+
df['Standing'].astype(str).isin(standing_sel) &
|
| 57 |
+
df['Dept Track'].astype(str).isin(dept_sel)
|
| 58 |
)
|
| 59 |
name_opts = sorted(df.loc[mask, 'Name'].astype(str).unique())
|
| 60 |
+
|
| 61 |
+
# Initialize or prune stored names
|
| 62 |
if 'names' not in st.session_state or st.session_state.names is None:
|
| 63 |
st.session_state.names = name_opts.copy()
|
| 64 |
else:
|
| 65 |
st.session_state.names = [n for n in st.session_state.names if n in name_opts]
|
| 66 |
+
|
| 67 |
name_sel = st.sidebar.multiselect(
|
| 68 |
+
"Select Faculty:",
|
| 69 |
+
options=name_opts,
|
| 70 |
+
default=st.session_state.names,
|
| 71 |
+
key='names'
|
| 72 |
)
|
| 73 |
|
| 74 |
# ---------------------------------------------------
|
|
|
|
| 76 |
# ---------------------------------------------------
|
| 77 |
st.title("Faculty Heatmap Explorer")
|
| 78 |
|
| 79 |
+
# Display heatmap (with optional row sums)
|
| 80 |
if not name_sel:
|
| 81 |
st.warning("No faculty selected — please choose at least one.")
|
| 82 |
+
fig = px.imshow(
|
| 83 |
+
[[0]],
|
| 84 |
+
labels={'x':'','y':'','color':'value'},
|
| 85 |
+
text_auto='.2f',
|
| 86 |
+
title="No faculty selected"
|
| 87 |
+
)
|
| 88 |
+
st.plotly_chart(fig, use_container_width=True)
|
| 89 |
else:
|
| 90 |
+
# Combine matrices
|
| 91 |
sum_df = None
|
| 92 |
for name in name_sel:
|
| 93 |
mat = filled_matrices[name]
|
| 94 |
sum_df = mat if sum_df is None else sum_df.add(mat, fill_value=0)
|
| 95 |
avg_df = sum_df.div(len(name_sel))
|
| 96 |
|
| 97 |
+
# Add a sum column on the right
|
| 98 |
+
avg_df_ext = avg_df.copy()
|
| 99 |
+
avg_df_ext['Sum'] = avg_df_ext.sum(axis=1)
|
| 100 |
+
|
| 101 |
+
# Wrap y-axis labels for compact display
|
| 102 |
+
wrapped_y = wrap_labels(list(avg_df_ext.index))
|
| 103 |
+
wrapped_x = list(avg_df_ext.columns)
|
| 104 |
+
|
| 105 |
+
# Create heatmap
|
| 106 |
+
fig = px.imshow(
|
| 107 |
+
avg_df_ext.values,
|
| 108 |
+
x=wrapped_x,
|
| 109 |
+
y=wrapped_y,
|
| 110 |
+
labels={'color':'Avg value'},
|
| 111 |
+
text_auto='.2f',
|
| 112 |
+
title=f"Avg Heatmap for {len(name_sel)} Faculty"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 113 |
)
|
| 114 |
+
fig.update_yaxes(autorange='reversed')
|
| 115 |
+
# Set a taller figure height for wide layout
|
| 116 |
+
fig.update_layout(height=800, margin=dict(l=70, r=70, t=70, b=70))
|
| 117 |
st.plotly_chart(fig, use_container_width=True)
|