github-actions[bot] commited on
Commit
5cf93b5
·
1 Parent(s): 5af8aff

Deploy from GitHub Actions

Browse files
Files changed (2) hide show
  1. components.py +41 -0
  2. pages.py +75 -43
components.py CHANGED
@@ -62,6 +62,42 @@ def render_sidebar_analyte_multiselect(
62
  )
63
 
64
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  def render_filtered_data_preview(
66
  df: pd.DataFrame,
67
  display_columns: List[str],
@@ -168,12 +204,17 @@ def render_records_by_year(raw_df: pd.DataFrame, reporting_month: int) -> None:
168
 
169
  yearly_data = yearly_data[["Reporting Year", "Reporting Period", "Records"]]
170
 
 
 
 
 
171
  st.dataframe(
172
  yearly_data.style.format(
173
  {"Records": "{:,}"}
174
  ), # use this instead of column_config for Records column
175
  hide_index=True,
176
  use_container_width=True,
 
177
  )
178
 
179
 
 
62
  )
63
 
64
 
65
+ def render_sidebar_analyte_pills(
66
+ all_analytes: List[str],
67
+ default_analytes: Optional[List[str]] = None,
68
+ key_prefix: str = "",
69
+ help_text: str = "Choose one or more analytes to display.",
70
+ ) -> List[str | None]:
71
+ """Render analyte pills"""
72
+ if default_analytes is None:
73
+ default_analytes = []
74
+
75
+ # Filter out any default values that aren't in the options list
76
+ valid_defaults = [
77
+ analyte for analyte in default_analytes if analyte in all_analytes
78
+ ]
79
+
80
+ widget_key = f"{key_prefix}_analyte_select"
81
+
82
+ if f"{widget_key}_previous_value" not in st.session_state:
83
+ values = valid_defaults
84
+ else:
85
+ values = st.session_state[f"{widget_key}_previous_value"]
86
+
87
+ def on_analyte_pills_change():
88
+ st.session_state[f"{widget_key}_previous_value"] = st.session_state[widget_key]
89
+
90
+ return st.sidebar.pills(
91
+ "Select Analytes:",
92
+ selection_mode="multi",
93
+ default=values,
94
+ options=all_analytes,
95
+ key=widget_key,
96
+ help=help_text,
97
+ on_change=on_analyte_pills_change,
98
+ )
99
+
100
+
101
  def render_filtered_data_preview(
102
  df: pd.DataFrame,
103
  display_columns: List[str],
 
204
 
205
  yearly_data = yearly_data[["Reporting Year", "Reporting Period", "Records"]]
206
 
207
+ row_height = 36
208
+ max_height = 600
209
+ calculated_height = min(len(yearly_data) * row_height, max_height) + 38
210
+
211
  st.dataframe(
212
  yearly_data.style.format(
213
  {"Records": "{:,}"}
214
  ), # use this instead of column_config for Records column
215
  hide_index=True,
216
  use_container_width=True,
217
+ height=calculated_height,
218
  )
219
 
220
 
pages.py CHANGED
@@ -22,7 +22,6 @@ from components import (
22
  render_correlation_plots,
23
  render_filtered_data_preview,
24
  render_sidebar_analyte_multiselect,
25
- render_sidebar_position_filter_selectbox,
26
  render_stations_map,
27
  )
28
  from dashboard_analytics import log_visit
@@ -350,46 +349,60 @@ def calendar_heatmaps_section():
350
  st.title("Calendar Heatmaps")
351
  st.info(
352
  """
353
- 💡 You can customize the colormaps using the **Plot Settings** expander in the sidebar.
354
-
355
  📅 Calendar heatmaps are grouped by calendar year instead of reporting year.
 
 
356
  """
357
  )
358
  raw_df = st.session_state.data["raw_df"]
359
  raw_df["Date"] = pd.to_datetime(raw_df["Activity_Start_Date_Time"]).dt.date
360
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
361
  default_analytes = [
362
  "Temperature, Water",
363
  "Dissolved Oxygen",
364
  "Salinity",
365
  "pH",
366
  "Turbidity",
367
- "Depth, Secchi Disk Depth",
368
- "Fecal Coliform (MPN)",
369
- "Total Nitrogen",
370
- "Total Phosphorus",
371
- "Chlorophyll-uncorrected",
372
  ]
373
 
374
  selected_analytes = render_sidebar_analyte_multiselect(
375
  all_analytes=sorted(raw_df["Org_Analyte_Name"].unique()),
376
  default_analytes=default_analytes,
377
  key_prefix="calendar",
378
- help_text="Choose one or more analytes to display in the heatmap.",
379
  )
380
  if not selected_analytes:
381
  st.warning("Please select at least one analyte to display.")
382
  return
383
 
384
  # Filter Options
385
- st.sidebar.markdown("### Filter Options")
386
- sector_filter = st.sidebar.selectbox(
387
- "Sector:",
388
- ["All"] + sorted(raw_df["Sector"].unique().tolist()),
389
- index=0,
390
- key="calendar_sector_select",
 
391
  )
392
- position_filter = render_sidebar_position_filter_selectbox(key_prefix="calendar")
393
 
394
  def format_colormap_option(option):
395
  append = ""
@@ -432,7 +445,7 @@ def calendar_heatmaps_section():
432
  `Depth, Secchi Disk Depth` : `Blues_r` _(reversed blues)_
433
  `All other analytes` : `Blues` _(blue)_
434
  """
435
- with st.sidebar.expander("Plot Settings", expanded=False):
436
  colormap = st.radio(
437
  "Color Scheme",
438
  options=[
@@ -467,14 +480,23 @@ def calendar_heatmaps_section():
467
 
468
  # Filter data
469
  plot_df = raw_df.copy()
 
 
 
 
 
470
  if sector_filter != "All":
471
  plot_df = plot_df[plot_df["Sector"] == sector_filter]
472
- if position_filter != "All":
473
- plot_df = plot_df[plot_df["Sample_Position"] == position_filter]
474
  if not plot_df.empty:
475
  for analyte in selected_analytes:
 
 
476
  try:
477
- fig = plot_calendar_heatmap(plot_df, analyte, colormap, position_filter)
 
 
478
  st.pyplot(fig)
479
  except ValueError as e:
480
  st.warning(str(e))
@@ -752,6 +774,23 @@ def trends_by_station_section():
752
  )
753
  )
754
  raw_df = st.session_state.data["raw_df"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
755
  default_analytes = [
756
  "Dissolved Oxygen",
757
  "Salinity",
@@ -762,21 +801,6 @@ def trends_by_station_section():
762
  "Total Nitrogen",
763
  "Total Phosphorus",
764
  ]
765
- st.sidebar.markdown("### Filter Options")
766
-
767
- selected_station = st.sidebar.selectbox(
768
- "Station:",
769
- sorted(raw_df["Station_Number"].unique()),
770
- index=sorted(raw_df["Station_Number"].unique()).index("3.20"),
771
- )
772
- selected_position = st.sidebar.segmented_control(
773
- "Sample Position:",
774
- ("All", "Surface", "Bottom"),
775
- default="All",
776
- selection_mode="single",
777
- )
778
- # if no position is selected, default to "All"
779
- selected_position = selected_position or "All"
780
  selected_analytes = render_sidebar_analyte_multiselect(
781
  all_analytes=sorted(raw_df["Org_Analyte_Name"].unique()),
782
  default_analytes=default_analytes,
@@ -786,20 +810,22 @@ def trends_by_station_section():
786
  st.warning("Please select at least one analyte to display.")
787
  return
788
 
 
 
 
 
 
 
 
 
789
  filtered_df = raw_df.query("Station_Number == @selected_station")
790
  if selected_position != "All":
791
  filtered_df = filtered_df.query("Sample_Position == @selected_position")
792
 
793
  csv_buffer = io.StringIO()
794
  filtered_df.to_csv(csv_buffer, index=False)
795
- st.sidebar.download_button(
796
- label="Download Filtered Data (CSV)",
797
- data=csv_buffer.getvalue(),
798
- file_name=f"station_{selected_station}_{selected_position.lower()}_data.csv",
799
- mime="text/csv",
800
- )
801
 
802
- with st.sidebar.expander("Preview Filtered Data"):
803
  display_columns = [
804
  "Activity_Start_Date_Time",
805
  "Sample_Position",
@@ -809,6 +835,12 @@ def trends_by_station_section():
809
  "Reporting_Year",
810
  ]
811
  render_filtered_data_preview(filtered_df, display_columns)
 
 
 
 
 
 
812
 
813
  if not filtered_df.empty:
814
  fig = plot_trends_by_station(filtered_df, selected_analytes, selected_position)
 
22
  render_correlation_plots,
23
  render_filtered_data_preview,
24
  render_sidebar_analyte_multiselect,
 
25
  render_stations_map,
26
  )
27
  from dashboard_analytics import log_visit
 
349
  st.title("Calendar Heatmaps")
350
  st.info(
351
  """
 
 
352
  📅 Calendar heatmaps are grouped by calendar year instead of reporting year.
353
+
354
+ 💡 You can customize the colormaps using the **Plot Settings** expander in the sidebar.
355
  """
356
  )
357
  raw_df = st.session_state.data["raw_df"]
358
  raw_df["Date"] = pd.to_datetime(raw_df["Activity_Start_Date_Time"]).dt.date
359
+ sector_filter = st.sidebar.selectbox(
360
+ "Sector:",
361
+ ["All"] + sorted(raw_df["Sector"].unique().tolist()),
362
+ index=0,
363
+ key="calendar_sector_select",
364
+ )
365
+ # Add year filter slider
366
+ years = sorted(raw_df["Activity_Start_Date_Time"].dt.year.unique())
367
+ default_min_year = 2018 if 2018 in years else min(years)
368
+ if len(years) >= 2:
369
+ year_range = st.sidebar.slider(
370
+ "Year Range:",
371
+ min_value=min(years),
372
+ max_value=max(years),
373
+ value=(default_min_year, max(years)),
374
+ key="calendar_year_range",
375
+ )
376
+ else:
377
+ year_range = (min(years), max(years))
378
  default_analytes = [
379
  "Temperature, Water",
380
  "Dissolved Oxygen",
381
  "Salinity",
382
  "pH",
383
  "Turbidity",
 
 
 
 
 
384
  ]
385
 
386
  selected_analytes = render_sidebar_analyte_multiselect(
387
  all_analytes=sorted(raw_df["Org_Analyte_Name"].unique()),
388
  default_analytes=default_analytes,
389
  key_prefix="calendar",
390
+ help_text="Select analytes to display.",
391
  )
392
  if not selected_analytes:
393
  st.warning("Please select at least one analyte to display.")
394
  return
395
 
396
  # Filter Options
397
+ # st.sidebar.markdown("### Filter Options")
398
+
399
+ selected_position = st.sidebar.segmented_control(
400
+ "Sample Position:",
401
+ ("Surface", "Bottom"),
402
+ default="Surface",
403
+ selection_mode="single",
404
  )
405
+ selected_position = selected_position or "Surface"
406
 
407
  def format_colormap_option(option):
408
  append = ""
 
445
  `Depth, Secchi Disk Depth` : `Blues_r` _(reversed blues)_
446
  `All other analytes` : `Blues` _(blue)_
447
  """
448
+ with st.sidebar.expander("Color Settings", expanded=False):
449
  colormap = st.radio(
450
  "Color Scheme",
451
  options=[
 
480
 
481
  # Filter data
482
  plot_df = raw_df.copy()
483
+ # Add year range filter
484
+ plot_df = plot_df[
485
+ (plot_df["Activity_Start_Date_Time"].dt.year >= year_range[0])
486
+ & (plot_df["Activity_Start_Date_Time"].dt.year <= year_range[1])
487
+ ]
488
  if sector_filter != "All":
489
  plot_df = plot_df[plot_df["Sector"] == sector_filter]
490
+ if selected_position != "All":
491
+ plot_df = plot_df[plot_df["Sample_Position"] == selected_position]
492
  if not plot_df.empty:
493
  for analyte in selected_analytes:
494
+ if not analyte:
495
+ continue
496
  try:
497
+ fig = plot_calendar_heatmap(
498
+ plot_df, analyte, colormap, selected_position
499
+ )
500
  st.pyplot(fig)
501
  except ValueError as e:
502
  st.warning(str(e))
 
774
  )
775
  )
776
  raw_df = st.session_state.data["raw_df"]
777
+ # Create a list of station options combining number and name
778
+ station_options = sorted(
779
+ [
780
+ f"{num}. {raw_df[raw_df['Station_Number'] == num]['Name'].iloc[0]}"
781
+ for num in sorted(raw_df["Station_Number"].unique())
782
+ ]
783
+ )
784
+
785
+ selected_station_full = st.sidebar.selectbox(
786
+ "Station:",
787
+ station_options,
788
+ index=station_options.index(
789
+ next(opt for opt in station_options if opt.startswith("3.20"))
790
+ ),
791
+ )
792
+ # Extract just the station number from the selection
793
+ selected_station = selected_station_full.split(". ")[0]
794
  default_analytes = [
795
  "Dissolved Oxygen",
796
  "Salinity",
 
801
  "Total Nitrogen",
802
  "Total Phosphorus",
803
  ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804
  selected_analytes = render_sidebar_analyte_multiselect(
805
  all_analytes=sorted(raw_df["Org_Analyte_Name"].unique()),
806
  default_analytes=default_analytes,
 
810
  st.warning("Please select at least one analyte to display.")
811
  return
812
 
813
+ selected_position = st.sidebar.segmented_control(
814
+ "Sample Position:",
815
+ ("Surface", "Bottom"),
816
+ default="Surface",
817
+ selection_mode="single",
818
+ )
819
+ selected_position = selected_position or "Surface"
820
+
821
  filtered_df = raw_df.query("Station_Number == @selected_station")
822
  if selected_position != "All":
823
  filtered_df = filtered_df.query("Sample_Position == @selected_position")
824
 
825
  csv_buffer = io.StringIO()
826
  filtered_df.to_csv(csv_buffer, index=False)
 
 
 
 
 
 
827
 
828
+ with st.sidebar.expander("View and Download Data"):
829
  display_columns = [
830
  "Activity_Start_Date_Time",
831
  "Sample_Position",
 
835
  "Reporting_Year",
836
  ]
837
  render_filtered_data_preview(filtered_df, display_columns)
838
+ st.download_button(
839
+ label="Download Station Data",
840
+ data=csv_buffer.getvalue(),
841
+ file_name=f"station_{selected_station}_{selected_position.lower()}_data.csv",
842
+ mime="text/csv",
843
+ )
844
 
845
  if not filtered_df.empty:
846
  fig = plot_trends_by_station(filtered_df, selected_analytes, selected_position)