Spaces:
Sleeping
Sleeping
streamlit.errors.StreamlitAPIException: The default value 'Galen Sasaki' is not part of the options.
Browse filesRemoved manual defaults for filters in session state; each multiselect now simply uses its full options list as the default.
On Clear All Filters, we reset standing, dept, and mark names for re-initialization.
For Faculty selection, we:
Initialize st.session_state.names to the available names on first load or after clear.
Prune it to remain a subset of the dynamically filtered name_opts.
Use that as the default, so you never get a “default not in options” error.
app.py
CHANGED
|
@@ -24,46 +24,50 @@ def wrap_labels(labels, width=40):
|
|
| 24 |
# Sidebar: Filters
|
| 25 |
# ---------------------------------------------------
|
| 26 |
st.sidebar.title("Filters")
|
| 27 |
-
# Ensure session state keys exist
|
| 28 |
-
if 'standing' not in st.session_state:
|
| 29 |
-
st.session_state.standing = sorted(df['Standing'].dropna().astype(str).unique())
|
| 30 |
-
if 'dept' not in st.session_state:
|
| 31 |
-
st.session_state.dept = sorted(df['Dept Track'].dropna().astype(str).unique())
|
| 32 |
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
st.session_state.dept = sorted(df['Dept Track'].dropna().astype(str).unique())
|
| 37 |
|
| 38 |
-
|
| 39 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 40 |
|
|
|
|
| 41 |
standing_sel = st.sidebar.multiselect(
|
| 42 |
"Filter by Standing:",
|
| 43 |
-
options=
|
| 44 |
-
default=
|
| 45 |
key='standing'
|
| 46 |
)
|
| 47 |
dept_sel = st.sidebar.multiselect(
|
| 48 |
"Filter by Dept Track:",
|
| 49 |
-
options=
|
| 50 |
-
default=
|
| 51 |
key='dept'
|
| 52 |
)
|
| 53 |
|
| 54 |
-
#
|
| 55 |
mask = (
|
| 56 |
df['Standing'].astype(str).isin(standing_sel) &
|
| 57 |
df['Dept Track'].astype(str).isin(dept_sel)
|
| 58 |
)
|
| 59 |
-
|
| 60 |
|
| 61 |
-
|
| 62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 63 |
|
|
|
|
| 64 |
name_sel = st.sidebar.multiselect(
|
| 65 |
"Select Faculty:",
|
| 66 |
-
options=
|
| 67 |
default=st.session_state.names,
|
| 68 |
key='names'
|
| 69 |
)
|
|
@@ -73,7 +77,7 @@ name_sel = st.sidebar.multiselect(
|
|
| 73 |
# ---------------------------------------------------
|
| 74 |
st.title("Faculty Heatmap Explorer")
|
| 75 |
|
| 76 |
-
#
|
| 77 |
if not name_sel:
|
| 78 |
st.warning("No faculty selected — please choose at least one.")
|
| 79 |
fig = px.imshow(
|
|
@@ -89,9 +93,9 @@ else:
|
|
| 89 |
sum_df = mat if sum_df is None else sum_df.add(mat, fill_value=0)
|
| 90 |
avg_df = sum_df.div(len(name_sel))
|
| 91 |
|
| 92 |
-
# Wrap
|
| 93 |
wrapped_y = wrap_labels(list(avg_df.index), width=40)
|
| 94 |
-
wrapped_x = list(avg_df.columns)
|
| 95 |
|
| 96 |
fig = px.imshow(
|
| 97 |
avg_df.values,
|
|
@@ -104,11 +108,10 @@ else:
|
|
| 104 |
fig.update_yaxes(autorange='reversed')
|
| 105 |
st.plotly_chart(fig, use_container_width=True)
|
| 106 |
|
| 107 |
-
#
|
| 108 |
st.subheader("Cell Details")
|
| 109 |
events = plotly_events(fig, click_event=True, key="heatmap")
|
| 110 |
if events:
|
| 111 |
-
# Determine original row & col from pointNumber
|
| 112 |
n_cols = avg_df.shape[1]
|
| 113 |
pt = events[0]
|
| 114 |
pt_num = pt.get('pointNumber', None)
|
|
@@ -118,11 +121,9 @@ else:
|
|
| 118 |
y_lab = avg_df.index[row_idx]
|
| 119 |
x_lab = avg_df.columns[col_idx]
|
| 120 |
else:
|
| 121 |
-
|
| 122 |
-
y_lab_wrapped = pt['y']
|
| 123 |
x_lab = pt['x']
|
| 124 |
-
|
| 125 |
-
y_lab = avg_df.index[wrapped_y.index(y_lab_wrapped)]
|
| 126 |
|
| 127 |
# Gather non-zero values
|
| 128 |
records = []
|
|
@@ -138,3 +139,4 @@ else:
|
|
| 138 |
st.info("No non-zero values for this cell.")
|
| 139 |
else:
|
| 140 |
st.write("Click on a heatmap cell to list faculty and their values.")
|
|
|
|
|
|
| 24 |
# Sidebar: Filters
|
| 25 |
# ---------------------------------------------------
|
| 26 |
st.sidebar.title("Filters")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
+
# Base options
|
| 29 |
+
def_opts = sorted(df['Dept Track'].dropna().astype(str).unique())
|
| 30 |
+
def_stand = sorted(df['Standing'].dropna().astype(str).unique())
|
|
|
|
| 31 |
|
| 32 |
+
# Clear filters button
|
| 33 |
+
if st.sidebar.button("Clear All Filters"):
|
| 34 |
+
st.session_state.standing = def_stand
|
| 35 |
+
st.session_state.dept = def_opts
|
| 36 |
+
# We'll reinitialize names below
|
| 37 |
+
st.session_state.names = None
|
| 38 |
|
| 39 |
+
# Multiselects for filters, store in session_state
|
| 40 |
standing_sel = st.sidebar.multiselect(
|
| 41 |
"Filter by Standing:",
|
| 42 |
+
options=def_stand,
|
| 43 |
+
default=def_stand,
|
| 44 |
key='standing'
|
| 45 |
)
|
| 46 |
dept_sel = st.sidebar.multiselect(
|
| 47 |
"Filter by Dept Track:",
|
| 48 |
+
options=def_opts,
|
| 49 |
+
default=def_opts,
|
| 50 |
key='dept'
|
| 51 |
)
|
| 52 |
|
| 53 |
+
# Determine available names based on current filters
|
| 54 |
mask = (
|
| 55 |
df['Standing'].astype(str).isin(standing_sel) &
|
| 56 |
df['Dept Track'].astype(str).isin(dept_sel)
|
| 57 |
)
|
| 58 |
+
name_opts = sorted(df.loc[mask, 'Name'].astype(str).unique())
|
| 59 |
|
| 60 |
+
# Initialize or clean session_state.names
|
| 61 |
+
if 'names' not in st.session_state or st.session_state.names is None:
|
| 62 |
+
st.session_state.names = name_opts.copy()
|
| 63 |
+
else:
|
| 64 |
+
# drop any names no longer in options
|
| 65 |
+
st.session_state.names = [n for n in st.session_state.names if n in name_opts]
|
| 66 |
|
| 67 |
+
# Faculty selection
|
| 68 |
name_sel = st.sidebar.multiselect(
|
| 69 |
"Select Faculty:",
|
| 70 |
+
options=name_opts,
|
| 71 |
default=st.session_state.names,
|
| 72 |
key='names'
|
| 73 |
)
|
|
|
|
| 77 |
# ---------------------------------------------------
|
| 78 |
st.title("Faculty Heatmap Explorer")
|
| 79 |
|
| 80 |
+
# Heatmap
|
| 81 |
if not name_sel:
|
| 82 |
st.warning("No faculty selected — please choose at least one.")
|
| 83 |
fig = px.imshow(
|
|
|
|
| 93 |
sum_df = mat if sum_df is None else sum_df.add(mat, fill_value=0)
|
| 94 |
avg_df = sum_df.div(len(name_sel))
|
| 95 |
|
| 96 |
+
# Wrap labels
|
| 97 |
wrapped_y = wrap_labels(list(avg_df.index), width=40)
|
| 98 |
+
wrapped_x = list(avg_df.columns)
|
| 99 |
|
| 100 |
fig = px.imshow(
|
| 101 |
avg_df.values,
|
|
|
|
| 108 |
fig.update_yaxes(autorange='reversed')
|
| 109 |
st.plotly_chart(fig, use_container_width=True)
|
| 110 |
|
| 111 |
+
# Cell details
|
| 112 |
st.subheader("Cell Details")
|
| 113 |
events = plotly_events(fig, click_event=True, key="heatmap")
|
| 114 |
if events:
|
|
|
|
| 115 |
n_cols = avg_df.shape[1]
|
| 116 |
pt = events[0]
|
| 117 |
pt_num = pt.get('pointNumber', None)
|
|
|
|
| 121 |
y_lab = avg_df.index[row_idx]
|
| 122 |
x_lab = avg_df.columns[col_idx]
|
| 123 |
else:
|
| 124 |
+
y_wrapped = pt['y']
|
|
|
|
| 125 |
x_lab = pt['x']
|
| 126 |
+
y_lab = avg_df.index[wrapped_y.index(y_wrapped)]
|
|
|
|
| 127 |
|
| 128 |
# Gather non-zero values
|
| 129 |
records = []
|
|
|
|
| 139 |
st.info("No non-zero values for this cell.")
|
| 140 |
else:
|
| 141 |
st.write("Click on a heatmap cell to list faculty and their values.")
|
| 142 |
+
|