igormolybog commited on
Commit
bdd9093
·
verified ·
1 Parent(s): 2d2f33e

fixed cosmetics

Browse files

Removed the broken st.experimental_rerun() and replaced it with st.session_state logic to reset filters.

Wrapped long row labels into multiple lines via a helper (using <br>), which compacts the heatmap.

Simplified Cell Details: clicking lists only the names & values in a table—no extra plots.

Files changed (1) hide show
  1. app.py +65 -61
app.py CHANGED
@@ -1,7 +1,7 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import numpy as np
4
- import base64, pickle
5
  import plotly.express as px
6
  from streamlit_plotly_events import plotly_events
7
 
@@ -14,35 +14,58 @@ df_encoded = "gASVJhkAAAAAAACMEXBhbmRhcy5jb3JlLmZyYW1llIwJRGF0YUZyYW1llJOUKYGUfZ
14
  filled_matrices = pickle.loads(base64.b64decode(filled_matrices_encoded))
15
  df = pickle.loads(base64.b64decode(df_encoded))
16
 
 
 
 
 
 
 
17
  # ---------------------------------------------------
18
  # Sidebar: Filters
19
  # ---------------------------------------------------
20
  st.sidebar.title("Filters")
21
- if st.sidebar.button("Clear All Filters"):
22
- st.experimental_rerun()
 
 
 
 
 
 
 
 
23
 
24
  standing_opts = sorted(df['Standing'].dropna().astype(str).unique())
25
  dept_opts = sorted(df['Dept Track'].dropna().astype(str).unique())
26
 
27
  standing_sel = st.sidebar.multiselect(
28
- "Filter by Standing:", standing_opts,
29
- default=standing_opts
 
 
30
  )
31
  dept_sel = st.sidebar.multiselect(
32
- "Filter by Dept Track:", dept_opts,
33
- default=dept_opts
 
 
34
  )
35
 
36
- # Autofilter names based on Standing & Dept
37
  mask = (
38
  df['Standing'].astype(str).isin(standing_sel) &
39
  df['Dept Track'].astype(str).isin(dept_sel)
40
  )
41
- all_names = sorted(df['Name'].astype(str).unique())
42
  name_options = sorted(df.loc[mask, 'Name'].astype(str).unique())
 
 
 
 
43
  name_sel = st.sidebar.multiselect(
44
- "Select Faculty:", name_options,
45
- default=name_options
 
 
46
  )
47
 
48
  # ---------------------------------------------------
@@ -50,26 +73,30 @@ name_sel = st.sidebar.multiselect(
50
  # ---------------------------------------------------
51
  st.title("Faculty Heatmap Explorer")
52
 
53
- # 1) Heatmap
54
  if not name_sel:
55
- st.write("**No faculty selected** — please select at least one name.")
56
  fig = px.imshow(
57
  [[0]], labels={'x':'','y':'','color':'value'},
58
  text_auto='.2f', title="No faculty selected"
59
  )
60
  st.plotly_chart(fig, use_container_width=True)
61
  else:
62
- # Sum and average matrices
63
  sum_df = None
64
  for name in name_sel:
65
  mat = filled_matrices[name]
66
  sum_df = mat if sum_df is None else sum_df.add(mat, fill_value=0)
67
  avg_df = sum_df.div(len(name_sel))
68
 
 
 
 
 
69
  fig = px.imshow(
70
- avg_df,
71
- x=avg_df.columns,
72
- y=avg_df.index,
73
  labels={'color':'Avg value'},
74
  text_auto='.2f',
75
  title=f"Avg Heatmap for {len(name_sel)} Faculty"
@@ -77,60 +104,37 @@ else:
77
  fig.update_yaxes(autorange='reversed')
78
  st.plotly_chart(fig, use_container_width=True)
79
 
80
- # 2) Click to show details
81
  st.subheader("Cell Details")
82
  events = plotly_events(fig, click_event=True, key="heatmap")
83
  if events:
84
- x_lab = events[0]['x']
85
- y_lab = events[0]['y']
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
  # Gather non-zero values
88
  records = []
89
  for name in name_sel:
90
  val = filled_matrices[name].at[y_lab, x_lab]
91
  if val != 0:
92
- row = df[df['Name']==name].iloc[0]
93
- records.append({
94
- 'Name': name,
95
- 'Value': val,
96
- 'Dept Track': str(row['Dept Track']),
97
- 'Standing': str(row['Standing'])
98
- })
99
 
100
  if records:
101
- detail_df = pd.DataFrame(records)
102
- # Dept Track distribution
103
- dept_df = (
104
- detail_df.groupby(['Dept Track','Value'])
105
- .size()
106
- .reset_index(name='Count')
107
- )
108
- fig_dept = px.line(
109
- dept_df,
110
- x='Value', y='Count',
111
- color='Dept Track', markers=True,
112
- title=f"Distribution by Dept Track (x={x_lab}, y={y_lab})"
113
- )
114
- st.plotly_chart(fig_dept, use_container_width=True)
115
-
116
- # Standing distribution
117
- stand_df = (
118
- detail_df.groupby(['Standing','Value'])
119
- .size()
120
- .reset_index(name='Count')
121
- )
122
- fig_st = px.line(
123
- stand_df,
124
- x='Value', y='Count',
125
- color='Standing', markers=True,
126
- title=f"Distribution by Standing (x={x_lab}, y={y_lab})"
127
- )
128
- st.plotly_chart(fig_st, use_container_width=True)
129
-
130
- # Table of non-zero values
131
- table_df = detail_df[['Name','Value']].sort_values('Value', ascending=False)
132
- st.dataframe(table_df)
133
  else:
134
- st.write("**No non-zero values for this cell.**")
135
  else:
136
- st.write("Click on a heatmap cell to see Dept/Standing distributions & values.")
 
1
  import streamlit as st
2
  import pandas as pd
3
  import numpy as np
4
+ import base64, pickle, textwrap
5
  import plotly.express as px
6
  from streamlit_plotly_events import plotly_events
7
 
 
14
  filled_matrices = pickle.loads(base64.b64decode(filled_matrices_encoded))
15
  df = pickle.loads(base64.b64decode(df_encoded))
16
 
17
+ # ---------------------------------------------------
18
+ # Helper: wrap long labels
19
+ # ---------------------------------------------------
20
+ def wrap_labels(labels, width=40):
21
+ return ["<br>".join(textwrap.wrap(lbl, width)) for lbl in labels]
22
+
23
  # ---------------------------------------------------
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
+ clear = st.sidebar.button("Clear All Filters")
34
+ if clear:
35
+ st.session_state.standing = sorted(df['Standing'].dropna().astype(str).unique())
36
+ st.session_state.dept = sorted(df['Dept Track'].dropna().astype(str).unique())
37
 
38
  standing_opts = sorted(df['Standing'].dropna().astype(str).unique())
39
  dept_opts = sorted(df['Dept Track'].dropna().astype(str).unique())
40
 
41
  standing_sel = st.sidebar.multiselect(
42
+ "Filter by Standing:",
43
+ options=standing_opts,
44
+ default=st.session_state.standing,
45
+ key='standing'
46
  )
47
  dept_sel = st.sidebar.multiselect(
48
+ "Filter by Dept Track:",
49
+ options=dept_opts,
50
+ default=st.session_state.dept,
51
+ key='dept'
52
  )
53
 
54
+ # Auto-filter names based on filters
55
  mask = (
56
  df['Standing'].astype(str).isin(standing_sel) &
57
  df['Dept Track'].astype(str).isin(dept_sel)
58
  )
 
59
  name_options = sorted(df.loc[mask, 'Name'].astype(str).unique())
60
+
61
+ if 'names' not in st.session_state or clear:
62
+ st.session_state.names = name_options
63
+
64
  name_sel = st.sidebar.multiselect(
65
+ "Select Faculty:",
66
+ options=name_options,
67
+ default=st.session_state.names,
68
+ key='names'
69
  )
70
 
71
  # ---------------------------------------------------
 
73
  # ---------------------------------------------------
74
  st.title("Faculty Heatmap Explorer")
75
 
76
+ # 1) Heatmap display
77
  if not name_sel:
78
+ st.warning("No faculty selected — please choose at least one.")
79
  fig = px.imshow(
80
  [[0]], labels={'x':'','y':'','color':'value'},
81
  text_auto='.2f', title="No faculty selected"
82
  )
83
  st.plotly_chart(fig, use_container_width=True)
84
  else:
85
+ # Sum & average
86
  sum_df = None
87
  for name in name_sel:
88
  mat = filled_matrices[name]
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 y labels (rows)
93
+ wrapped_y = wrap_labels(list(avg_df.index), width=40)
94
+ wrapped_x = list(avg_df.columns) # x labels usually short
95
+
96
  fig = px.imshow(
97
+ avg_df.values,
98
+ x=wrapped_x,
99
+ y=wrapped_y,
100
  labels={'color':'Avg value'},
101
  text_auto='.2f',
102
  title=f"Avg Heatmap for {len(name_sel)} Faculty"
 
104
  fig.update_yaxes(autorange='reversed')
105
  st.plotly_chart(fig, use_container_width=True)
106
 
107
+ # 2) Click-to-list values
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)
115
+ if pt_num is not None:
116
+ row_idx = pt_num // n_cols
117
+ col_idx = pt_num % n_cols
118
+ y_lab = avg_df.index[row_idx]
119
+ x_lab = avg_df.columns[col_idx]
120
+ else:
121
+ # fallback: use string labels (unlikely)
122
+ y_lab_wrapped = pt['y']
123
+ x_lab = pt['x']
124
+ # map back wrapped to original
125
+ y_lab = avg_df.index[wrapped_y.index(y_lab_wrapped)]
126
 
127
  # Gather non-zero values
128
  records = []
129
  for name in name_sel:
130
  val = filled_matrices[name].at[y_lab, x_lab]
131
  if val != 0:
132
+ records.append({'Name': name, 'Value': val})
 
 
 
 
 
 
133
 
134
  if records:
135
+ detail_df = pd.DataFrame(records).sort_values('Value', ascending=False)
136
+ st.table(detail_df)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  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.")