github-actions[bot] commited on
Commit
fecd908
·
1 Parent(s): 89cc124

Deploy from GitHub Actions

Browse files
Files changed (5) hide show
  1. analysis.py +222 -13
  2. app.py +2 -0
  3. pages.py +7 -0
  4. ui/pages/grouped_bar_charts.py +53 -1
  5. ui/pages/sector_compare.py +112 -0
analysis.py CHANGED
@@ -501,7 +501,7 @@ def plot_sector_trends(
501
 
502
  # For Salinity, exclude Fresh Water Lakes
503
  if analyte_name == "Salinity":
504
- analyte_data = analyte_data[analyte_data["Sector"] != "Fresh Water Lakes"]
505
 
506
  # Plot each sector with custom colors
507
  for sector, color in zip(df["Sector"].unique(), custom_colors):
@@ -2207,7 +2207,7 @@ def plot_grouped_bars(
2207
  parameter: str,
2208
  year_range: tuple[int, int],
2209
  group_by: str = "sector",
2210
- ) -> Figure:
2211
  """
2212
  Create a grouped bar chart showing means by sector or year for a selected parameter.
2213
 
@@ -2224,8 +2224,9 @@ def plot_grouped_bars(
2224
 
2225
  Returns:
2226
  --------
2227
- Figure
2228
- Matplotlib figure containing the grouped bar chart
 
2229
  """
2230
  # Filter data for parameter and year range
2231
  plot_df = df[
@@ -2330,9 +2331,9 @@ def plot_grouped_bars(
2330
 
2331
  # Customize plot
2332
  unit = plot_df["Org_Result_Unit"].iloc[0]
2333
- # ax.set_ylabel(f"{parameter} ({unit})")
2334
  ax.set_xlabel(x_label)
2335
- ax.set_title(f"{parameter} (Mean Annual {unit})")
 
2336
 
2337
  # Function to wrap text
2338
  def wrap_labels(text, width=10):
@@ -2359,7 +2360,7 @@ def plot_grouped_bars(
2359
  # Add error bar note with adjusted position
2360
  ax.text(
2361
  0.99,
2362
- -0.15, # Moved down slightly to accommodate wrapped labels
2363
  "Error bars represent ±1 standard error of the mean",
2364
  ha="right",
2365
  va="top",
@@ -2369,7 +2370,7 @@ def plot_grouped_bars(
2369
  )
2370
 
2371
  # Adjust layout with more vertical space for wrapped labels
2372
- plt.tight_layout(rect=(0, 0.2, 1, 1)) # Increased bottom padding
2373
 
2374
  # Add grid
2375
  ax.grid(True, axis="y", alpha=0.2, linestyle="-", zorder=1)
@@ -2377,12 +2378,10 @@ def plot_grouped_bars(
2377
  # Customize spines
2378
  ax.spines["top"].set_visible(False)
2379
  ax.spines["right"].set_visible(False)
2380
- ax.spines["left"].set_visible(False) # Add this line to remove left spine
2381
 
2382
  # Remove tick marks but keep labels
2383
- ax.tick_params(
2384
- axis="y", which="both", length=0
2385
- ) # Add this line to remove tick marks
2386
 
2387
  ax.legend(
2388
  bbox_to_anchor=(1.02, 1), # Position at top-right
@@ -2403,7 +2402,8 @@ def plot_grouped_bars(
2403
  ax.set_yscale("log")
2404
  ax.yaxis.set_major_formatter(plt.ScalarFormatter()) # type: ignore
2405
 
2406
- return fig
 
2407
 
2408
 
2409
  def plot_seasonal_line(
@@ -2687,3 +2687,212 @@ def plot_seasonal_line(
2687
  plt.tight_layout(rect=(0, 0, 0.9, 1))
2688
  stats_df.insert(0, "parameter", parameter)
2689
  return fig, param_data, stats_df
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
 
502
  # For Salinity, exclude Fresh Water Lakes
503
  if analyte_name == "Salinity":
504
+ analyte_data = analyte_data[analyte_data["Sector"] != "Freshwater Lakes"]
505
 
506
  # Plot each sector with custom colors
507
  for sector, color in zip(df["Sector"].unique(), custom_colors):
 
2207
  parameter: str,
2208
  year_range: tuple[int, int],
2209
  group_by: str = "sector",
2210
+ ) -> tuple[Figure, pd.DataFrame]:
2211
  """
2212
  Create a grouped bar chart showing means by sector or year for a selected parameter.
2213
 
 
2224
 
2225
  Returns:
2226
  --------
2227
+ tuple[Figure, pd.DataFrame]
2228
+ - Figure: Matplotlib figure containing the grouped bar chart
2229
+ - DataFrame: Contains the plotted data points with means and standard errors
2230
  """
2231
  # Filter data for parameter and year range
2232
  plot_df = df[
 
2331
 
2332
  # Customize plot
2333
  unit = plot_df["Org_Result_Unit"].iloc[0]
 
2334
  ax.set_xlabel(x_label)
2335
+ title = f"{parameter} (Mean Annual{' ' + unit if unit else ''})"
2336
+ ax.set_title(title)
2337
 
2338
  # Function to wrap text
2339
  def wrap_labels(text, width=10):
 
2360
  # Add error bar note with adjusted position
2361
  ax.text(
2362
  0.99,
2363
+ -0.15,
2364
  "Error bars represent ±1 standard error of the mean",
2365
  ha="right",
2366
  va="top",
 
2370
  )
2371
 
2372
  # Adjust layout with more vertical space for wrapped labels
2373
+ plt.tight_layout(rect=(0, 0.2, 1, 1))
2374
 
2375
  # Add grid
2376
  ax.grid(True, axis="y", alpha=0.2, linestyle="-", zorder=1)
 
2378
  # Customize spines
2379
  ax.spines["top"].set_visible(False)
2380
  ax.spines["right"].set_visible(False)
2381
+ ax.spines["left"].set_visible(False)
2382
 
2383
  # Remove tick marks but keep labels
2384
+ ax.tick_params(axis="y", which="both", length=0)
 
 
2385
 
2386
  ax.legend(
2387
  bbox_to_anchor=(1.02, 1), # Position at top-right
 
2402
  ax.set_yscale("log")
2403
  ax.yaxis.set_major_formatter(plt.ScalarFormatter()) # type: ignore
2404
 
2405
+ means_df.insert(0, "parameter", parameter)
2406
+ return fig, means_df
2407
 
2408
 
2409
  def plot_seasonal_line(
 
2687
  plt.tight_layout(rect=(0, 0, 0.9, 1))
2688
  stats_df.insert(0, "parameter", parameter)
2689
  return fig, param_data, stats_df
2690
+
2691
+
2692
+ @timer(include_params=True)
2693
+ def plot_sector_line_charts(
2694
+ df: pd.DataFrame,
2695
+ parameter: str,
2696
+ show_sem: bool = True,
2697
+ panel_chart: bool = False,
2698
+ ) -> tuple[Figure, pd.DataFrame, pd.DataFrame]:
2699
+ """
2700
+ Create a plot of mean annual parameter trends by sector.
2701
+
2702
+ Parameters:
2703
+ -----------
2704
+ df : pd.DataFrame
2705
+ Input dataframe
2706
+ parameter : str
2707
+ Name of the parameter to plot
2708
+ show_sem : bool, default=True
2709
+ Whether to show the standard error of the mean bands
2710
+ panel_chart : bool, default=False
2711
+ If True, creates a grid of individual sector charts instead of overlapping lines
2712
+
2713
+ Returns:
2714
+ --------
2715
+ tuple[Figure, pd.DataFrame, pd.DataFrame]
2716
+ - Figure: Matplotlib figure containing the line chart(s)
2717
+ - DataFrame: Filtered dataframe containing the data used in the plot
2718
+ - DataFrame: Contains the plotted data points with means and standard errors
2719
+ """
2720
+ # Filter data for parameter
2721
+ param_data = df[df["Org_Analyte_Name"] == parameter].copy()
2722
+
2723
+ # For Salinity, exclude Freshwater Lakes
2724
+ if parameter == "Salinity":
2725
+ param_data = param_data[param_data["Sector"] != "Freshwater Lakes"]
2726
+
2727
+ # Get unique sectors and years
2728
+ sectors = sorted(param_data["Sector"].unique())
2729
+ years = sorted(param_data["Reporting_Year"].unique())
2730
+ n_sectors = len(sectors)
2731
+
2732
+ # Calculate grid dimensions for panel chart
2733
+ if panel_chart:
2734
+ n_cols = min(3, n_sectors) # Maximum 3 columns
2735
+ n_rows = (n_sectors + n_cols - 1) // n_cols
2736
+ fig = plt.figure(figsize=(5 * n_cols, 3 * n_rows))
2737
+ else:
2738
+ fig, ax = plt.subplots(figsize=(14, 4))
2739
+
2740
+ custom_colors = [
2741
+ "#1f77b4", # blue
2742
+ "#ff7f0e", # orange
2743
+ "#2ca02c", # green
2744
+ "#d62728", # red
2745
+ "#9467bd", # purple
2746
+ "#8c564b", # brown
2747
+ "#e377c2", # pink
2748
+ "#7f7f7f", # gray
2749
+ ]
2750
+
2751
+ # Initialize empty list to store sector data
2752
+ all_sector_data = []
2753
+
2754
+ # Get global y-axis limits for consistent scaling
2755
+ y_min = float("inf")
2756
+ y_max = float("-inf")
2757
+
2758
+ # First pass to get y-axis limits
2759
+ for sector in sectors:
2760
+ sector_data = (
2761
+ param_data[param_data["Sector"] == sector]
2762
+ .groupby("Reporting_Year", observed=True)["Org_Result_Value"]
2763
+ .agg(["mean", "sem"])
2764
+ .reset_index()
2765
+ )
2766
+ if not sector_data.empty:
2767
+ y_min = min(y_min, (sector_data["mean"] - sector_data["sem"]).min())
2768
+ y_max = max(y_max, (sector_data["mean"] + sector_data["sem"]).max())
2769
+
2770
+ # Plot each sector
2771
+ for i, (sector, color) in enumerate(zip(sectors, custom_colors)):
2772
+ sector_data = (
2773
+ param_data[param_data["Sector"] == sector]
2774
+ .groupby("Reporting_Year", observed=True)["Org_Result_Value"]
2775
+ .agg(["mean", "sem"])
2776
+ .reset_index()
2777
+ )
2778
+
2779
+ # Add sector column to the data
2780
+ sector_data["Sector"] = sector
2781
+ all_sector_data.append(sector_data)
2782
+
2783
+ if not sector_data.empty:
2784
+ if panel_chart:
2785
+ ax = fig.add_subplot(n_rows, n_cols, i + 1)
2786
+
2787
+ # Plot mean line with error bands for this sector
2788
+ ax.plot(
2789
+ sector_data["Reporting_Year"],
2790
+ sector_data["mean"],
2791
+ "-o",
2792
+ color=color,
2793
+ markersize=4,
2794
+ linewidth=2,
2795
+ )
2796
+
2797
+ if show_sem:
2798
+ ax.fill_between(
2799
+ sector_data["Reporting_Year"],
2800
+ sector_data["mean"] - sector_data["sem"],
2801
+ sector_data["mean"] + sector_data["sem"],
2802
+ color=color,
2803
+ alpha=0.15,
2804
+ )
2805
+
2806
+ # Customize individual panel
2807
+ ax.set_title(sector, pad=10, fontsize=10)
2808
+ ax.grid(True, axis="y", alpha=0.2, linestyle="--")
2809
+ ax.spines["top"].set_visible(False)
2810
+ ax.spines["right"].set_visible(False)
2811
+ ax.spines["left"].set_visible(False)
2812
+ ax.tick_params(axis="y", which="both", length=0)
2813
+ ax.set_xticks(years)
2814
+ ax.set_xticklabels(years, rotation=45)
2815
+
2816
+ # Set consistent y-axis limits
2817
+ if parameter in [
2818
+ "Turbidity",
2819
+ "Fecal Coliform (MPN)",
2820
+ "Total Nitrogen",
2821
+ "Total Phosphorus",
2822
+ ]:
2823
+ ax.set_yscale("log")
2824
+ else:
2825
+ ax.set_ylim(y_min * 0.95, y_max * 1.05)
2826
+
2827
+ else:
2828
+ # Original single-panel plotting code
2829
+ ax.plot(
2830
+ sector_data["Reporting_Year"],
2831
+ sector_data["mean"],
2832
+ "-o",
2833
+ color=color,
2834
+ label=sector,
2835
+ markersize=4,
2836
+ linewidth=2,
2837
+ )
2838
+
2839
+ if show_sem:
2840
+ ax.fill_between(
2841
+ sector_data["Reporting_Year"],
2842
+ sector_data["mean"] - sector_data["sem"],
2843
+ sector_data["mean"] + sector_data["sem"],
2844
+ color=color,
2845
+ alpha=0.15,
2846
+ )
2847
+
2848
+ # Get parameter unit
2849
+ param_unit = param_data["Org_Result_Unit"].iloc[0] if not param_data.empty else ""
2850
+
2851
+ if panel_chart:
2852
+ # Add common title and labels
2853
+ fig.suptitle(f"{parameter} ({param_unit})", fontsize=14, y=1.02)
2854
+ fig.text(0.5, 0.02, "Year", ha="center", fontsize=12)
2855
+ fig.text(
2856
+ 0.02,
2857
+ 0.5,
2858
+ f"Value ({param_unit})",
2859
+ va="center",
2860
+ rotation="vertical",
2861
+ fontsize=12,
2862
+ )
2863
+ else:
2864
+ # Original single-panel customization
2865
+ ax.set_title(parameter, pad=10, fontsize=14, fontweight="normal")
2866
+ ax.set_xlabel("Year", fontsize=12)
2867
+ ax.set_ylabel(f"{parameter} ({param_unit})", fontsize=12)
2868
+ ax.set_xticks(years)
2869
+ ax.set_xticklabels(years)
2870
+ ax.grid(True, axis="y", alpha=0.2, linestyle="--")
2871
+ ax.spines["top"].set_visible(False)
2872
+ ax.spines["right"].set_visible(False)
2873
+ ax.spines["left"].set_visible(False)
2874
+ ax.tick_params(axis="y", which="both", length=0)
2875
+ ax.legend(
2876
+ bbox_to_anchor=(1.05, 1),
2877
+ loc="upper left",
2878
+ borderaxespad=0.0,
2879
+ frameon=False,
2880
+ fontsize=9,
2881
+ )
2882
+
2883
+ if parameter in [
2884
+ "Turbidity",
2885
+ "Fecal Coliform (MPN)",
2886
+ "Total Nitrogen",
2887
+ "Total Phosphorus",
2888
+ ]:
2889
+ ax.set_yscale("log")
2890
+
2891
+ # Adjust layout
2892
+ plt.tight_layout()
2893
+
2894
+ # Combine all sector data into a single dataframe
2895
+ plot_data = pd.concat(all_sector_data, ignore_index=True)
2896
+ plot_data.insert(0, "parameter", parameter)
2897
+
2898
+ return fig, param_data, plot_data
app.py CHANGED
@@ -16,6 +16,7 @@ from pages import (
16
  scatter_plots_page,
17
  seasonal_line_charts_page,
18
  seasonal_trends_page,
 
19
  sector_trends_page,
20
  settings_page,
21
  trends_by_station_page,
@@ -47,6 +48,7 @@ page_dict = {}
47
 
48
  page_dict["Annual Report Draft Charts/Tables"] = [
49
  seasonal_line_charts_page,
 
50
  scatter_plots_page,
51
  grouped_bar_charts_page,
52
  parameter_summary_tables_page,
 
16
  scatter_plots_page,
17
  seasonal_line_charts_page,
18
  seasonal_trends_page,
19
+ sector_compare_page,
20
  sector_trends_page,
21
  settings_page,
22
  trends_by_station_page,
 
48
 
49
  page_dict["Annual Report Draft Charts/Tables"] = [
50
  seasonal_line_charts_page,
51
+ sector_compare_page,
52
  scatter_plots_page,
53
  grouped_bar_charts_page,
54
  parameter_summary_tables_page,
pages.py CHANGED
@@ -855,6 +855,12 @@ def trends_by_station_section():
855
  )
856
 
857
 
 
 
 
 
 
 
858
  home_page = st.Page(
859
  home_section,
860
  title="Home",
@@ -953,4 +959,5 @@ __all__ = [
953
  "scatter_plots_page",
954
  "grouped_bar_charts_page",
955
  "seasonal_line_charts_page",
 
956
  ]
 
855
  )
856
 
857
 
858
+ sector_compare_page = st.Page(
859
+ "ui/pages/sector_compare.py",
860
+ title="Sector Comparison",
861
+ icon=":material/ssid_chart:",
862
+ )
863
+
864
  home_page = st.Page(
865
  home_section,
866
  title="Home",
 
959
  "scatter_plots_page",
960
  "grouped_bar_charts_page",
961
  "seasonal_line_charts_page",
962
+ "sector_compare_page",
963
  ]
ui/pages/grouped_bar_charts.py CHANGED
@@ -1,7 +1,10 @@
 
 
1
  import pandas as pd
2
  import streamlit as st
3
 
4
  from analysis import plot_grouped_bars
 
5
  from dashboard_analytics import log_visit
6
 
7
  st.title("Grouped Bar Charts")
@@ -46,7 +49,56 @@ else:
46
  year_range = (min(years), max(years))
47
 
48
  try:
49
- fig = plot_grouped_bars(raw_df, selected_parameter, year_range, group_by)
50
  st.pyplot(fig)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  except ValueError as e:
52
  st.warning(str(e))
 
1
+ import io
2
+
3
  import pandas as pd
4
  import streamlit as st
5
 
6
  from analysis import plot_grouped_bars
7
+ from components import render_filtered_data_preview
8
  from dashboard_analytics import log_visit
9
 
10
  st.title("Grouped Bar Charts")
 
49
  year_range = (min(years), max(years))
50
 
51
  try:
52
+ fig, means_df = plot_grouped_bars(raw_df, selected_parameter, year_range, group_by)
53
  st.pyplot(fig)
54
+
55
+ # Add Chart Data expander
56
+ with st.expander("Chart Data"):
57
+ render_filtered_data_preview(
58
+ means_df, display_columns=means_df.columns.tolist()
59
+ )
60
+
61
+ # Add CSV download button for chart data
62
+ csv_buffer = io.StringIO()
63
+ means_df.to_csv(csv_buffer, index=False)
64
+ st.download_button(
65
+ label=f"Download Chart Data for {selected_parameter} (CSV)",
66
+ data=csv_buffer.getvalue(),
67
+ file_name=f"{selected_parameter}_grouped_by_{group_by}_year-{year_range[0]}-{year_range[1]}_chart_data.csv",
68
+ mime="text/csv",
69
+ )
70
+
71
+ # Add Raw Data expander
72
+ with st.expander("Raw Data"):
73
+ # Filter raw data for the selected parameter and year range
74
+ filtered_df = raw_df[
75
+ (raw_df["Org_Analyte_Name"] == selected_parameter)
76
+ & (raw_df["Activity_Start_Date_Time"].dt.year >= year_range[0])
77
+ & (raw_df["Activity_Start_Date_Time"].dt.year <= year_range[1])
78
+ ]
79
+
80
+ # Display filtered data preview
81
+ render_filtered_data_preview(
82
+ filtered_df,
83
+ [
84
+ "Date",
85
+ "Sector",
86
+ "Station_Number",
87
+ "Sample_Position",
88
+ "Org_Analyte_Name",
89
+ "Org_Result_Value",
90
+ ],
91
+ )
92
+
93
+ # Add CSV download button for raw data
94
+ csv_buffer = io.StringIO()
95
+ filtered_df.to_csv(csv_buffer, index=False)
96
+ st.download_button(
97
+ label=f"Download Raw Data for {selected_parameter} (CSV)",
98
+ data=csv_buffer.getvalue(),
99
+ file_name=f"{selected_parameter}_grouped_by_{group_by}_year-{year_range[0]}-{year_range[1]}_raw_data.csv",
100
+ mime="text/csv",
101
+ )
102
+
103
  except ValueError as e:
104
  st.warning(str(e))
ui/pages/sector_compare.py ADDED
@@ -0,0 +1,112 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import io
2
+
3
+ import pandas as pd
4
+ import streamlit as st
5
+
6
+ from analysis import plot_sector_line_charts
7
+ from components import render_filtered_data_preview
8
+ from dashboard_analytics import log_visit
9
+
10
+ st.title("Sector Comparison Charts")
11
+ log_visit("Sector Comparison Charts")
12
+
13
+ # Get data from session state
14
+ raw_df = st.session_state.data["raw_df"]
15
+ raw_df["Date"] = pd.to_datetime(raw_df["Activity_Start_Date_Time"]).dt.date
16
+
17
+ # Create sidebar controls
18
+ selected_parameter = st.sidebar.selectbox(
19
+ "Parameter:",
20
+ options=sorted(raw_df["Org_Analyte_Name"].unique()),
21
+ index=sorted(raw_df["Org_Analyte_Name"].unique()).index("Temperature, Water")
22
+ if "Temperature, Water" in raw_df["Org_Analyte_Name"].unique()
23
+ else 0,
24
+ help="Select a parameter to display.",
25
+ key="sector_compare_parameter_select",
26
+ )
27
+
28
+ # Add show_sem checkbox
29
+ show_sem = st.sidebar.checkbox(
30
+ "Show Standard Error",
31
+ value=True,
32
+ help="Display standard error bands around the mean lines",
33
+ key="sector_compare_show_sem",
34
+ )
35
+
36
+ # Add year filter slider
37
+ years = sorted(raw_df["Activity_Start_Date_Time"].dt.year.unique())
38
+ default_min_year = min(years)
39
+ if len(years) >= 2:
40
+ year_range = st.sidebar.slider(
41
+ "Year Range:",
42
+ min_value=min(years),
43
+ max_value=max(years),
44
+ value=(default_min_year, max(years)),
45
+ key="sector_compare_year_range",
46
+ )
47
+ else:
48
+ year_range = (min(years), max(years))
49
+
50
+ # Filter data based on year range
51
+ filtered_raw_df = raw_df[
52
+ (raw_df["Activity_Start_Date_Time"].dt.year >= year_range[0])
53
+ & (raw_df["Activity_Start_Date_Time"].dt.year <= year_range[1])
54
+ ]
55
+
56
+ try:
57
+ fig, param_data, plot_data = plot_sector_line_charts(
58
+ filtered_raw_df, selected_parameter, show_sem=show_sem
59
+ )
60
+ st.pyplot(fig)
61
+
62
+ fig, _, _ = plot_sector_line_charts(
63
+ filtered_raw_df, selected_parameter, show_sem=show_sem, panel_chart=True
64
+ )
65
+ st.pyplot(fig)
66
+
67
+ # Add Chart Data expander
68
+ with st.expander("Chart Data"):
69
+ render_filtered_data_preview(
70
+ plot_data, display_columns=plot_data.columns.tolist()
71
+ )
72
+
73
+ # Add CSV download button for chart data
74
+ csv_buffer = io.StringIO()
75
+ plot_data.to_csv(csv_buffer, index=False)
76
+ st.download_button(
77
+ label=f"Download Chart Data for {selected_parameter} (CSV)",
78
+ data=csv_buffer.getvalue(),
79
+ file_name=f"{selected_parameter}_sector_comparison_year-{year_range[0]}-{year_range[1]}_chart_data.csv",
80
+ mime="text/csv",
81
+ )
82
+
83
+ # Add Raw Data expander
84
+ with st.expander("Raw Data"):
85
+ # Filter raw data for the selected parameter
86
+ filtered_df = param_data.copy()
87
+
88
+ # Display filtered data preview
89
+ render_filtered_data_preview(
90
+ filtered_df,
91
+ [
92
+ "Date",
93
+ "Sector",
94
+ "Station_Number",
95
+ "Sample_Position",
96
+ "Org_Analyte_Name",
97
+ "Org_Result_Value",
98
+ ],
99
+ )
100
+
101
+ # Add CSV download button for raw data
102
+ csv_buffer = io.StringIO()
103
+ filtered_df.to_csv(csv_buffer, index=False)
104
+ st.download_button(
105
+ label=f"Download Raw Data for {selected_parameter} (CSV)",
106
+ data=csv_buffer.getvalue(),
107
+ file_name=f"{selected_parameter}_sector_comparison_year-{year_range[0]}-{year_range[1]}_raw_data.csv",
108
+ mime="text/csv",
109
+ )
110
+
111
+ except ValueError as e:
112
+ st.warning(str(e))