github-actions[bot] commited on
Commit ·
3a1dc7d
1
Parent(s): d055b25
Add all files with LFS support
Browse files- analysis.py +69 -20
- app.py +17 -14
- main.py +3 -0
analysis.py
CHANGED
|
@@ -922,13 +922,16 @@ def plot_seasonal_salinity(
|
|
| 922 |
basemap_provider,
|
| 923 |
alpha=0.5,
|
| 924 |
shapefile_path="data/SAB/SAB.shp",
|
|
|
|
| 925 |
):
|
| 926 |
"""
|
| 927 |
Create seasonal plots of mean salinity values by WBID with basemap.
|
|
|
|
| 928 |
|
| 929 |
Args:
|
| 930 |
salinity_data: DataFrame containing salinity measurements
|
| 931 |
-
year: Year to filter data for (str)
|
|
|
|
| 932 |
"""
|
| 933 |
# Read and filter WBIDs
|
| 934 |
wbids = gpd.read_file(shapefile_path)
|
|
@@ -937,20 +940,29 @@ def plot_seasonal_salinity(
|
|
| 937 |
wbids = wbids.to_crs(epsg=3857)
|
| 938 |
|
| 939 |
# Process data - create a copy to avoid SettingWithCopyWarning
|
| 940 |
-
year_data = salinity_data[
|
| 941 |
-
|
| 942 |
-
|
| 943 |
-
|
| 944 |
-
|
| 945 |
-
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 949 |
)
|
| 950 |
|
| 951 |
-
# Calculate
|
| 952 |
seasonal_means = (
|
| 953 |
-
year_data.groupby(["WBID", "
|
| 954 |
.mean()
|
| 955 |
.reset_index()
|
| 956 |
)
|
|
@@ -989,11 +1001,38 @@ def plot_seasonal_salinity(
|
|
| 989 |
bottom=0.05, # Slightly increased bottom margin to give more space
|
| 990 |
)
|
| 991 |
|
| 992 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
ax = fig.add_subplot(gs[idx // 2, idx % 2])
|
| 994 |
|
| 995 |
-
|
| 996 |
-
merged = wbids.merge(
|
| 997 |
|
| 998 |
# Plot WBIDs
|
| 999 |
merged.plot(
|
|
@@ -1010,15 +1049,23 @@ def plot_seasonal_salinity(
|
|
| 1010 |
|
| 1011 |
ax.set_xlim(extent[0], extent[1])
|
| 1012 |
ax.set_ylim(extent[2], extent[3])
|
| 1013 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1014 |
if idx < 2: # Top row
|
| 1015 |
ax.set_title(
|
| 1016 |
-
f"
|
| 1017 |
-
|
|
|
|
|
|
|
| 1018 |
else: # Bottom row
|
| 1019 |
ax.set_title(
|
| 1020 |
-
f"
|
| 1021 |
-
|
|
|
|
|
|
|
| 1022 |
ax.set_axis_off()
|
| 1023 |
|
| 1024 |
# Add colorbar
|
|
@@ -1045,6 +1092,7 @@ def plot_seasonal_salinity_for_bays(
|
|
| 1045 |
alpha=0.5,
|
| 1046 |
shapefile_path="data/SAB/SAB.shp",
|
| 1047 |
wbids=None,
|
|
|
|
| 1048 |
):
|
| 1049 |
"""
|
| 1050 |
Create seasonal plots of mean salinity values by WBID for N, E, W, SAB, GL and Lake Powell.
|
|
@@ -1062,6 +1110,7 @@ def plot_seasonal_salinity_for_bays(
|
|
| 1062 |
basemap_provider=basemap_provider,
|
| 1063 |
alpha=alpha,
|
| 1064 |
shapefile_path=shapefile_path,
|
|
|
|
| 1065 |
)
|
| 1066 |
return fig
|
| 1067 |
|
|
|
|
| 922 |
basemap_provider,
|
| 923 |
alpha=0.5,
|
| 924 |
shapefile_path="data/SAB/SAB.shp",
|
| 925 |
+
reporting_end_month: int = 10,
|
| 926 |
):
|
| 927 |
"""
|
| 928 |
Create seasonal plots of mean salinity values by WBID with basemap.
|
| 929 |
+
Uses configurable Reporting Year with meteorological seasons.
|
| 930 |
|
| 931 |
Args:
|
| 932 |
salinity_data: DataFrame containing salinity measurements
|
| 933 |
+
year: Reporting Year to filter data for (str)
|
| 934 |
+
reporting_end_month: Last month of the reporting year (1-12, default=10 for October)
|
| 935 |
"""
|
| 936 |
# Read and filter WBIDs
|
| 937 |
wbids = gpd.read_file(shapefile_path)
|
|
|
|
| 940 |
wbids = wbids.to_crs(epsg=3857)
|
| 941 |
|
| 942 |
# Process data - create a copy to avoid SettingWithCopyWarning
|
| 943 |
+
year_data = salinity_data[salinity_data["Reporting_Year"] == int(year)].copy()
|
| 944 |
+
|
| 945 |
+
# Function to determine quarter based on date and reporting year end
|
| 946 |
+
def get_quarter(date, reporting_end_month):
|
| 947 |
+
month = date.month
|
| 948 |
+
|
| 949 |
+
# Calculate month offset to align with reporting year
|
| 950 |
+
month_offset = (12 - reporting_end_month) % 12
|
| 951 |
+
|
| 952 |
+
# Adjust month to align with reporting year
|
| 953 |
+
adjusted_month = ((month + month_offset) % 12) or 12
|
| 954 |
+
|
| 955 |
+
# Determine quarter (1-4)
|
| 956 |
+
return f"Q{((adjusted_month - 1) // 3) + 1}"
|
| 957 |
+
|
| 958 |
+
# Add quarter column
|
| 959 |
+
year_data.loc[:, "quarter"] = year_data["Activity_Start_Date_Time"].apply(
|
| 960 |
+
lambda x: get_quarter(x, reporting_end_month)
|
| 961 |
)
|
| 962 |
|
| 963 |
+
# Calculate quarterly means
|
| 964 |
seasonal_means = (
|
| 965 |
+
year_data.groupby(["WBID", "quarter"], observed=True)["Salinity"]
|
| 966 |
.mean()
|
| 967 |
.reset_index()
|
| 968 |
)
|
|
|
|
| 1001 |
bottom=0.05, # Slightly increased bottom margin to give more space
|
| 1002 |
)
|
| 1003 |
|
| 1004 |
+
# Function to get quarter date range
|
| 1005 |
+
def get_quarter_dates(quarter: str, year: int, reporting_end_month: int) -> str:
|
| 1006 |
+
# Calculate first month of reporting year
|
| 1007 |
+
first_month = (reporting_end_month % 12) + 1
|
| 1008 |
+
|
| 1009 |
+
# Calculate start month for each quarter
|
| 1010 |
+
quarter_num = int(quarter[1])
|
| 1011 |
+
start_month = ((first_month - 1 + ((quarter_num - 1) * 3)) % 12) + 1
|
| 1012 |
+
end_month = ((start_month + 2) % 12) or 12
|
| 1013 |
+
|
| 1014 |
+
# For Reporting Year X, the start date is actually in year X-1 if the month
|
| 1015 |
+
# is after the reporting end month
|
| 1016 |
+
start_year = int(year) - 1 if start_month > reporting_end_month else int(year)
|
| 1017 |
+
end_year = start_year
|
| 1018 |
+
if end_month < start_month:
|
| 1019 |
+
end_year += 1
|
| 1020 |
+
|
| 1021 |
+
start_date = pd.Timestamp(f"{start_year}-{start_month:02d}-01")
|
| 1022 |
+
end_date = pd.Timestamp(
|
| 1023 |
+
f"{end_year}-{end_month:02d}-{pd.Timestamp(f'{end_year}-{end_month:02d}').days_in_month}"
|
| 1024 |
+
)
|
| 1025 |
+
|
| 1026 |
+
return f"{start_date.strftime('%b %d, %Y')} - {end_date.strftime('%b %d, %Y')}"
|
| 1027 |
+
|
| 1028 |
+
# Use quarters instead of seasons
|
| 1029 |
+
quarters = ["Q1", "Q2", "Q3", "Q4"]
|
| 1030 |
+
|
| 1031 |
+
for idx, quarter in enumerate(quarters):
|
| 1032 |
ax = fig.add_subplot(gs[idx // 2, idx % 2])
|
| 1033 |
|
| 1034 |
+
quarter_data = seasonal_means[seasonal_means["quarter"] == quarter]
|
| 1035 |
+
merged = wbids.merge(quarter_data, on="WBID", how="left")
|
| 1036 |
|
| 1037 |
# Plot WBIDs
|
| 1038 |
merged.plot(
|
|
|
|
| 1049 |
|
| 1050 |
ax.set_xlim(extent[0], extent[1])
|
| 1051 |
ax.set_ylim(extent[2], extent[3])
|
| 1052 |
+
|
| 1053 |
+
# Get date range for this quarter
|
| 1054 |
+
date_range = get_quarter_dates(quarter, int(year), reporting_end_month)
|
| 1055 |
+
|
| 1056 |
+
# Create title with two lines
|
| 1057 |
if idx < 2: # Top row
|
| 1058 |
ax.set_title(
|
| 1059 |
+
f"Quarter {quarter[1]} Mean Salinity\n{date_range}",
|
| 1060 |
+
pad=15,
|
| 1061 |
+
fontsize=10,
|
| 1062 |
+
)
|
| 1063 |
else: # Bottom row
|
| 1064 |
ax.set_title(
|
| 1065 |
+
f"Quarter {quarter[1]} Mean Salinity\n{date_range}",
|
| 1066 |
+
pad=5,
|
| 1067 |
+
fontsize=10,
|
| 1068 |
+
)
|
| 1069 |
ax.set_axis_off()
|
| 1070 |
|
| 1071 |
# Add colorbar
|
|
|
|
| 1092 |
alpha=0.5,
|
| 1093 |
shapefile_path="data/SAB/SAB.shp",
|
| 1094 |
wbids=None,
|
| 1095 |
+
reporting_end_month: int = 10,
|
| 1096 |
):
|
| 1097 |
"""
|
| 1098 |
Create seasonal plots of mean salinity values by WBID for N, E, W, SAB, GL and Lake Powell.
|
|
|
|
| 1110 |
basemap_provider=basemap_provider,
|
| 1111 |
alpha=alpha,
|
| 1112 |
shapefile_path=shapefile_path,
|
| 1113 |
+
reporting_end_month=reporting_end_month,
|
| 1114 |
)
|
| 1115 |
return fig
|
| 1116 |
|
app.py
CHANGED
|
@@ -480,7 +480,11 @@ def generate_seasonal_plot(data, year, shapefile_path):
|
|
| 480 |
)
|
| 481 |
|
| 482 |
return plot_seasonal_salinity_for_bays(
|
| 483 |
-
data,
|
|
|
|
|
|
|
|
|
|
|
|
|
| 484 |
)
|
| 485 |
|
| 486 |
|
|
@@ -1158,19 +1162,18 @@ elif section == "Calendar Heatmaps":
|
|
| 1158 |
elif section == "Seasonal Trends":
|
| 1159 |
st.title("Seasonal Trends")
|
| 1160 |
raw_df = data["raw_df"]
|
| 1161 |
-
|
| 1162 |
-
|
| 1163 |
-
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
|
| 1170 |
-
|
| 1171 |
-
|
| 1172 |
-
|
| 1173 |
-
)
|
| 1174 |
if not raw_df.empty:
|
| 1175 |
seasonal_data = load_seasonal_data(raw_df, analyte)
|
| 1176 |
fig = generate_seasonal_plot(
|
|
|
|
| 480 |
)
|
| 481 |
|
| 482 |
return plot_seasonal_salinity_for_bays(
|
| 483 |
+
data,
|
| 484 |
+
year,
|
| 485 |
+
shapefile_path=shapefile_path,
|
| 486 |
+
wbids=wbids,
|
| 487 |
+
reporting_end_month=st.session_state.dataset_reporting_month,
|
| 488 |
)
|
| 489 |
|
| 490 |
|
|
|
|
| 1162 |
elif section == "Seasonal Trends":
|
| 1163 |
st.title("Seasonal Trends")
|
| 1164 |
raw_df = data["raw_df"]
|
| 1165 |
+
# Use Reporting_Year instead of calendar year
|
| 1166 |
+
years = sorted(raw_df["Reporting_Year"].unique())
|
| 1167 |
+
|
| 1168 |
+
# Move filters to sidebar
|
| 1169 |
+
st.sidebar.markdown("### Filter Options")
|
| 1170 |
+
analyte = st.sidebar.selectbox(
|
| 1171 |
+
"Select Analyte:", ["Salinity"], index=0, key="seasonal_analyte_select"
|
| 1172 |
+
)
|
| 1173 |
+
selected_year = st.sidebar.selectbox(
|
| 1174 |
+
"Select Year:", sorted(years, reverse=True), index=0, key="seasonal_year_select"
|
| 1175 |
+
)
|
| 1176 |
+
|
|
|
|
| 1177 |
if not raw_df.empty:
|
| 1178 |
seasonal_data = load_seasonal_data(raw_df, analyte)
|
| 1179 |
fig = generate_seasonal_plot(
|
main.py
CHANGED
|
@@ -73,6 +73,7 @@ def get_analyte_data_with_lat_long(df: pd.DataFrame, analyte: str) -> pd.DataFra
|
|
| 73 |
- Station_Number
|
| 74 |
- Org_Analyte_Name
|
| 75 |
- Org_Result_Value
|
|
|
|
| 76 |
analyte (str): Name of the analyte to filter for (e.g., "Temperature, Water")
|
| 77 |
|
| 78 |
Returns:
|
|
@@ -85,6 +86,7 @@ def get_analyte_data_with_lat_long(df: pd.DataFrame, analyte: str) -> pd.DataFra
|
|
| 85 |
- Activity_Depth: Depth of measurement
|
| 86 |
- Latitude: Station latitude
|
| 87 |
- Longitude: Station longitude
|
|
|
|
| 88 |
- {analyte}: Measured value for the specified analyte
|
| 89 |
|
| 90 |
Note:
|
|
@@ -104,6 +106,7 @@ def get_analyte_data_with_lat_long(df: pd.DataFrame, analyte: str) -> pd.DataFra
|
|
| 104 |
"Activity_Depth",
|
| 105 |
"Latitude",
|
| 106 |
"Longitude",
|
|
|
|
| 107 |
],
|
| 108 |
values="Org_Result_Value",
|
| 109 |
aggfunc="mean",
|
|
|
|
| 73 |
- Station_Number
|
| 74 |
- Org_Analyte_Name
|
| 75 |
- Org_Result_Value
|
| 76 |
+
- Reporting_Year
|
| 77 |
analyte (str): Name of the analyte to filter for (e.g., "Temperature, Water")
|
| 78 |
|
| 79 |
Returns:
|
|
|
|
| 86 |
- Activity_Depth: Depth of measurement
|
| 87 |
- Latitude: Station latitude
|
| 88 |
- Longitude: Station longitude
|
| 89 |
+
- Reporting_Year: Reporting year
|
| 90 |
- {analyte}: Measured value for the specified analyte
|
| 91 |
|
| 92 |
Note:
|
|
|
|
| 106 |
"Activity_Depth",
|
| 107 |
"Latitude",
|
| 108 |
"Longitude",
|
| 109 |
+
"Reporting_Year",
|
| 110 |
],
|
| 111 |
values="Org_Result_Value",
|
| 112 |
aggfunc="mean",
|