github-actions[bot] commited on
Commit ·
69abaa3
1
Parent(s): 2dc4d04
Deploy from GitHub Actions
Browse files- plots/map.py +223 -200
- ui/pages/seasonal_maps.py +1 -0
plots/map.py
CHANGED
|
@@ -13,204 +13,203 @@ from osgeo import gdal
|
|
| 13 |
|
| 14 |
from utils.data_loading import timer
|
| 15 |
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
| 92 |
-
|
| 93 |
-
|
| 94 |
-
|
| 95 |
-
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
| 125 |
-
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
|
| 129 |
-
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
| 157 |
-
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
| 170 |
-
|
| 171 |
-
|
| 172 |
-
|
| 173 |
-
|
| 174 |
-
|
| 175 |
-
|
| 176 |
-
|
| 177 |
-
|
| 178 |
-
|
| 179 |
-
|
| 180 |
-
|
| 181 |
-
|
| 182 |
-
|
| 183 |
-
|
| 184 |
-
|
| 185 |
-
|
| 186 |
-
|
| 187 |
-
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
| 191 |
-
|
| 192 |
-
|
| 193 |
-
|
| 194 |
-
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
|
| 198 |
-
|
| 199 |
-
|
| 200 |
-
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
return fig
|
| 214 |
|
| 215 |
|
| 216 |
@timer(include_params=True)
|
|
@@ -490,9 +489,10 @@ def add_colorbar(
|
|
| 490 |
# Get value range
|
| 491 |
vmin = seasonal_means[parameter].min()
|
| 492 |
vmax = get_parameter_max_value(parameter, seasonal_means[parameter].max())
|
|
|
|
| 493 |
|
| 494 |
# Create colorbar
|
| 495 |
-
norm = plt.Normalize(vmin=vmin, vmax=vmax) # type: ignore
|
| 496 |
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
|
| 497 |
sm.set_array([])
|
| 498 |
|
|
@@ -500,6 +500,29 @@ def add_colorbar(
|
|
| 500 |
unit = get_parameter_unit(parameter)
|
| 501 |
label = f"{parameter} ({unit})" if unit else parameter
|
| 502 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 503 |
# Add colorbar to figure
|
| 504 |
fig.colorbar(
|
| 505 |
sm,
|
|
@@ -508,7 +531,7 @@ def add_colorbar(
|
|
| 508 |
label=label,
|
| 509 |
pad=0.01,
|
| 510 |
fraction=0.015,
|
| 511 |
-
ticks=
|
| 512 |
)
|
| 513 |
|
| 514 |
|
|
|
|
| 13 |
|
| 14 |
from utils.data_loading import timer
|
| 15 |
|
| 16 |
+
# def plot_seasonal_salinity(
|
| 17 |
+
# salinity_data: pd.DataFrame,
|
| 18 |
+
# year: str,
|
| 19 |
+
# basemap_provider,
|
| 20 |
+
# alpha=0.5,
|
| 21 |
+
# shapefile_path="data/SAB/SAB.shp",
|
| 22 |
+
# reporting_end_month: int = 10,
|
| 23 |
+
# ):
|
| 24 |
+
# """
|
| 25 |
+
# Create seasonal plots of mean salinity values by WBID with basemap.
|
| 26 |
+
# Uses configurable Reporting Year with meteorological seasons.
|
| 27 |
+
|
| 28 |
+
# Args:
|
| 29 |
+
# salinity_data: DataFrame containing salinity measurements
|
| 30 |
+
# year: Reporting Year to filter data for (str)
|
| 31 |
+
# reporting_end_month: Last month of the reporting year (1-12, default=10 for October)
|
| 32 |
+
# """
|
| 33 |
+
# # Read and filter WBIDs
|
| 34 |
+
# wbids = gpd.read_file(shapefile_path)
|
| 35 |
+
# relevant_wbids = salinity_data["WBID"].unique()
|
| 36 |
+
# wbids = wbids[wbids["WBID"].isin(relevant_wbids)]
|
| 37 |
+
# wbids = wbids.to_crs(epsg=3857)
|
| 38 |
+
|
| 39 |
+
# # Process data - create a copy to avoid SettingWithCopyWarning
|
| 40 |
+
# year_data = salinity_data[salinity_data["Reporting_Year"] == int(year)].copy()
|
| 41 |
+
|
| 42 |
+
# # Function to determine quarter based on date and reporting year end
|
| 43 |
+
# def get_quarter(date, reporting_end_month):
|
| 44 |
+
# month = date.month
|
| 45 |
+
|
| 46 |
+
# # Calculate month offset to align with reporting year
|
| 47 |
+
# month_offset = (12 - reporting_end_month) % 12
|
| 48 |
+
|
| 49 |
+
# # Adjust month to align with reporting year
|
| 50 |
+
# adjusted_month = ((month + month_offset) % 12) or 12
|
| 51 |
+
|
| 52 |
+
# # Determine quarter (1-4)
|
| 53 |
+
# return f"Q{((adjusted_month - 1) // 3) + 1}"
|
| 54 |
+
|
| 55 |
+
# # Add quarter column
|
| 56 |
+
# year_data.loc[:, "quarter"] = year_data["Activity_Start_Date_Time"].apply(
|
| 57 |
+
# lambda x: get_quarter(x, reporting_end_month)
|
| 58 |
+
# )
|
| 59 |
+
|
| 60 |
+
# # Calculate quarterly means
|
| 61 |
+
# seasonal_means = (
|
| 62 |
+
# year_data.groupby(["WBID", "quarter"], observed=True)["Salinity"]
|
| 63 |
+
# .mean()
|
| 64 |
+
# .reset_index()
|
| 65 |
+
# )
|
| 66 |
+
|
| 67 |
+
# fig = plt.figure(figsize=(20, 14))
|
| 68 |
+
|
| 69 |
+
# # Create custom colormap with focused range
|
| 70 |
+
# colors = ["#08519c", "#73a9cf", "#fee090", "#fc8d59", "#d73027"]
|
| 71 |
+
# cmap = LinearSegmentedColormap.from_list("custom", colors, N=100)
|
| 72 |
+
|
| 73 |
+
# # Get global min/max for consistent colormap
|
| 74 |
+
# vmin = seasonal_means["Salinity"].min()
|
| 75 |
+
# vmax = 40
|
| 76 |
+
|
| 77 |
+
# # Calculate map extent
|
| 78 |
+
# bounds = wbids.total_bounds
|
| 79 |
+
# x_buffer = (bounds[2] - bounds[0]) * 0.05
|
| 80 |
+
# y_buffer = (bounds[3] - bounds[1]) * 0.05
|
| 81 |
+
# extent = [
|
| 82 |
+
# bounds[0] - x_buffer,
|
| 83 |
+
# bounds[2] + x_buffer,
|
| 84 |
+
# bounds[1] - y_buffer,
|
| 85 |
+
# bounds[3] + y_buffer,
|
| 86 |
+
# ]
|
| 87 |
+
|
| 88 |
+
# # Create subplots with tighter spacing
|
| 89 |
+
# gs = fig.add_gridspec(
|
| 90 |
+
# 2,
|
| 91 |
+
# 2,
|
| 92 |
+
# width_ratios=[1, 1],
|
| 93 |
+
# wspace=0.05, # Minimal horizontal space between plots
|
| 94 |
+
# hspace=-0.15, # More negative value to further reduce vertical space
|
| 95 |
+
# left=0.02, # Left margin
|
| 96 |
+
# right=0.98, # Right margin
|
| 97 |
+
# top=0.95, # Slightly reduced top margin to give more space
|
| 98 |
+
# bottom=0.05, # Slightly increased bottom margin to give more space
|
| 99 |
+
# )
|
| 100 |
+
|
| 101 |
+
# # Function to get quarter date range
|
| 102 |
+
# def get_quarter_dates(quarter: str, year: int, reporting_end_month: int) -> str:
|
| 103 |
+
# # Calculate first month of reporting year
|
| 104 |
+
# first_month = (reporting_end_month % 12) + 1
|
| 105 |
+
|
| 106 |
+
# # Calculate start month for each quarter
|
| 107 |
+
# quarter_num = int(quarter[1])
|
| 108 |
+
# start_month = ((first_month - 1 + ((quarter_num - 1) * 3)) % 12) + 1
|
| 109 |
+
# end_month = ((start_month + 2) % 12) or 12
|
| 110 |
+
|
| 111 |
+
# # For Reporting Year X, the start date is actually in year X-1 if the month
|
| 112 |
+
# # is after the reporting end month
|
| 113 |
+
# start_year = int(year) - 1 if start_month > reporting_end_month else int(year)
|
| 114 |
+
# end_year = start_year
|
| 115 |
+
# if end_month < start_month:
|
| 116 |
+
# end_year += 1
|
| 117 |
+
|
| 118 |
+
# start_date = pd.Timestamp(f"{start_year}-{start_month:02d}-01")
|
| 119 |
+
# end_date = pd.Timestamp(
|
| 120 |
+
# f"{end_year}-{end_month:02d}-{pd.Timestamp(f'{end_year}-{end_month:02d}').days_in_month}"
|
| 121 |
+
# )
|
| 122 |
+
|
| 123 |
+
# return f"{start_date.strftime('%b %d, %Y')} - {end_date.strftime('%b %d, %Y')}"
|
| 124 |
+
|
| 125 |
+
# # Use quarters instead of seasons
|
| 126 |
+
# quarters = ["Q1", "Q2", "Q3", "Q4"]
|
| 127 |
+
|
| 128 |
+
# for idx, quarter in enumerate(quarters):
|
| 129 |
+
# ax = fig.add_subplot(gs[idx // 2, idx % 2])
|
| 130 |
+
|
| 131 |
+
# quarter_data = seasonal_means[seasonal_means["quarter"] == quarter]
|
| 132 |
+
# merged = wbids.merge(quarter_data, on="WBID", how="left")
|
| 133 |
+
|
| 134 |
+
# # Plot WBIDs
|
| 135 |
+
# merged.plot(
|
| 136 |
+
# column="Salinity",
|
| 137 |
+
# ax=ax,
|
| 138 |
+
# cmap=cmap,
|
| 139 |
+
# vmin=vmin,
|
| 140 |
+
# vmax=vmax,
|
| 141 |
+
# alpha=0.7,
|
| 142 |
+
# missing_kwds={"color": "lightgrey", "alpha": 0.5},
|
| 143 |
+
# )
|
| 144 |
+
|
| 145 |
+
# ctx.add_basemap(ax, source=basemap_provider, zoom=11, alpha=alpha) # type: ignore
|
| 146 |
+
|
| 147 |
+
# ax.set_xlim(extent[0], extent[1])
|
| 148 |
+
# ax.set_ylim(extent[2], extent[3])
|
| 149 |
+
|
| 150 |
+
# # Get date range for this quarter
|
| 151 |
+
# date_range = get_quarter_dates(quarter, int(year), reporting_end_month)
|
| 152 |
+
|
| 153 |
+
# # Create title with two lines
|
| 154 |
+
# if idx < 2: # Top row
|
| 155 |
+
# ax.set_title(
|
| 156 |
+
# f"Quarter {quarter[1]} Mean Salinity\n{date_range}",
|
| 157 |
+
# pad=15,
|
| 158 |
+
# fontsize=10,
|
| 159 |
+
# )
|
| 160 |
+
# else: # Bottom row
|
| 161 |
+
# ax.set_title(
|
| 162 |
+
# f"Quarter {quarter[1]} Mean Salinity\n{date_range}",
|
| 163 |
+
# pad=5,
|
| 164 |
+
# fontsize=10,
|
| 165 |
+
# )
|
| 166 |
+
# ax.set_axis_off()
|
| 167 |
+
|
| 168 |
+
# # Add colorbar
|
| 169 |
+
# norm = plt.Normalize(vmin=vmin, vmax=vmax) # type: ignore
|
| 170 |
+
# sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
|
| 171 |
+
# sm.set_array([])
|
| 172 |
+
# fig.colorbar(
|
| 173 |
+
# sm,
|
| 174 |
+
# ax=fig.axes,
|
| 175 |
+
# orientation="vertical",
|
| 176 |
+
# label="Salinity (ppt)",
|
| 177 |
+
# pad=0.01,
|
| 178 |
+
# fraction=0.015,
|
| 179 |
+
# ticks=np.arange(0, 45, 5), # Add ticks every 5 units
|
| 180 |
+
# )
|
| 181 |
+
|
| 182 |
+
# return fig
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# def plot_seasonal_salinity_for_bays(
|
| 186 |
+
# salinity_data: pd.DataFrame,
|
| 187 |
+
# year: str,
|
| 188 |
+
# basemap_provider=ctx.providers.USGS.USTopo, # type: ignore
|
| 189 |
+
# alpha=0.5,
|
| 190 |
+
# shapefile_path="data/SAB/SAB.shp",
|
| 191 |
+
# wbids=None,
|
| 192 |
+
# reporting_end_month: int = 10,
|
| 193 |
+
# ):
|
| 194 |
+
# """
|
| 195 |
+
# Create seasonal plots of mean salinity values by WBID for N, E, W, SAB, GL and Lake Powell.
|
| 196 |
+
# """
|
| 197 |
+
# if wbids is None:
|
| 198 |
+
# wbids = gpd.read_file(shapefile_path)
|
| 199 |
+
# if wbids.crs is None:
|
| 200 |
+
# wbids.set_crs(epsg=6439, inplace=True)
|
| 201 |
+
# wbids = wbids.to_crs(epsg=3857)
|
| 202 |
+
# fig = plot_seasonal_salinity(
|
| 203 |
+
# salinity_data.query(
|
| 204 |
+
# "WBID.isin(['1061A', '1061B', '1061C', '1061D', '1061E', '1061F', '1061G', '1061H', '1055A'])"
|
| 205 |
+
# ),
|
| 206 |
+
# year=year,
|
| 207 |
+
# basemap_provider=basemap_provider,
|
| 208 |
+
# alpha=alpha,
|
| 209 |
+
# shapefile_path=shapefile_path,
|
| 210 |
+
# reporting_end_month=reporting_end_month,
|
| 211 |
+
# )
|
| 212 |
+
# return fig
|
|
|
|
| 213 |
|
| 214 |
|
| 215 |
@timer(include_params=True)
|
|
|
|
| 489 |
# Get value range
|
| 490 |
vmin = seasonal_means[parameter].min()
|
| 491 |
vmax = get_parameter_max_value(parameter, seasonal_means[parameter].max())
|
| 492 |
+
data_max = seasonal_means[parameter].max()
|
| 493 |
|
| 494 |
# Create colorbar
|
| 495 |
+
norm = plt.Normalize(vmin=vmin, vmax=vmax if vmax is not None else data_max) # type: ignore
|
| 496 |
sm = plt.cm.ScalarMappable(cmap=cmap, norm=norm)
|
| 497 |
sm.set_array([])
|
| 498 |
|
|
|
|
| 500 |
unit = get_parameter_unit(parameter)
|
| 501 |
label = f"{parameter} ({unit})" if unit else parameter
|
| 502 |
|
| 503 |
+
# Calculate appropriate tick spacing based on data range
|
| 504 |
+
if vmax is not None:
|
| 505 |
+
if vmax <= 1:
|
| 506 |
+
tick_spacing = 0.1
|
| 507 |
+
elif vmax <= 10:
|
| 508 |
+
tick_spacing = 1
|
| 509 |
+
elif vmax <= 50:
|
| 510 |
+
tick_spacing = 5
|
| 511 |
+
else:
|
| 512 |
+
tick_spacing = 10
|
| 513 |
+
ticks = np.arange(0, vmax + tick_spacing, tick_spacing)
|
| 514 |
+
else:
|
| 515 |
+
# Use data_max with automatic tick spacing
|
| 516 |
+
if data_max <= 1:
|
| 517 |
+
tick_spacing = 0.1
|
| 518 |
+
elif data_max <= 10:
|
| 519 |
+
tick_spacing = 1
|
| 520 |
+
elif data_max <= 50:
|
| 521 |
+
tick_spacing = 5
|
| 522 |
+
else:
|
| 523 |
+
tick_spacing = 10
|
| 524 |
+
ticks = np.arange(0, data_max + tick_spacing, tick_spacing)
|
| 525 |
+
|
| 526 |
# Add colorbar to figure
|
| 527 |
fig.colorbar(
|
| 528 |
sm,
|
|
|
|
| 531 |
label=label,
|
| 532 |
pad=0.01,
|
| 533 |
fraction=0.015,
|
| 534 |
+
ticks=ticks,
|
| 535 |
)
|
| 536 |
|
| 537 |
|
ui/pages/seasonal_maps.py
CHANGED
|
@@ -70,6 +70,7 @@ if not raw_df.empty:
|
|
| 70 |
"Activity_Start_Date_Time",
|
| 71 |
"Reporting_Year",
|
| 72 |
"WBID",
|
|
|
|
| 73 |
"Station_Number",
|
| 74 |
"Sample_Position",
|
| 75 |
"Org_Analyte_Name",
|
|
|
|
| 70 |
"Activity_Start_Date_Time",
|
| 71 |
"Reporting_Year",
|
| 72 |
"WBID",
|
| 73 |
+
"Sector",
|
| 74 |
"Station_Number",
|
| 75 |
"Sample_Position",
|
| 76 |
"Org_Analyte_Name",
|