Spaces:
Sleeping
Sleeping
Fix function structure and remove duplicates
Browse files- Moved process_daily_snow to module level so both calculate_total_new_snow and create_plots can use it
- Removed duplicate create_plots function
- Removed orphaned code blocks
- Fixed calculate_total_new_snow to properly return calculated total
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
app.py
CHANGED
|
@@ -158,16 +158,21 @@ def calculate_total_new_snow(df):
|
|
| 158 |
lambda x: x.date() if x.hour >= 9 else (x - pd.Timedelta(days=1)).date()
|
| 159 |
)
|
| 160 |
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
|
| 170 |
-
|
| 171 |
|
| 172 |
def create_plots(df):
|
| 173 |
"""Create all weather plots including SWE estimates"""
|
|
@@ -251,121 +256,16 @@ def create_plots(df):
|
|
| 251 |
fig_rose.subplots_adjust(top=0.95, bottom=0.05, left=0.1, right=0.95)
|
| 252 |
|
| 253 |
return fig, fig_rose
|
| 254 |
-
|
| 255 |
-
def process_daily_snow(group):
|
| 256 |
-
"""Sum up ONLY the 3-hour snowfall amounts for each day period"""
|
| 257 |
-
# Sort by time to ensure proper sequence
|
| 258 |
-
group = group.sort_values('datetime')
|
| 259 |
-
|
| 260 |
-
# Print debugging information
|
| 261 |
-
print(f"\nSnowfall amounts for {group['day_group'].iloc[0]}:")
|
| 262 |
-
for _, row in group.iterrows():
|
| 263 |
-
if pd.notna(row['snowfall_3hr']):
|
| 264 |
-
print(f"{row['datetime'].strftime('%Y-%m-%d %H:%M')}: {row['snowfall_3hr']} inches")
|
| 265 |
-
|
| 266 |
-
# Sum only the valid 3-hour amounts, treating NaN as 0
|
| 267 |
-
valid_amounts = group['snowfall_3hr'].fillna(0)
|
| 268 |
-
daily_total = valid_amounts.sum()
|
| 269 |
-
|
| 270 |
-
print(f"Daily total: {daily_total} inches")
|
| 271 |
-
return daily_total
|
| 272 |
-
|
| 273 |
-
# Calculate daily snow totals
|
| 274 |
-
daily_totals = snow_df.groupby('day_group').apply(process_daily_snow)
|
| 275 |
-
|
| 276 |
-
return daily_totals.sum()
|
| 277 |
|
| 278 |
def create_wind_rose(df, ax):
|
| 279 |
"""Create a wind rose plot"""
|
| 280 |
if not isinstance(ax, WindroseAxes):
|
| 281 |
ax = WindroseAxes.from_ax(ax=ax)
|
| 282 |
-
ax.bar(df['wind_dir_deg'].dropna(), df['wind_speed'].dropna(),
|
| 283 |
bins=np.arange(0, 40, 5), normed=True, opening=0.8, edgecolor='white')
|
| 284 |
ax.set_legend(title='Wind Speed (mph)')
|
| 285 |
ax.set_title('Wind Rose')
|
| 286 |
|
| 287 |
-
def create_plots(df):
|
| 288 |
-
"""Create all weather plots including SWE estimates"""
|
| 289 |
-
# Create figure with adjusted height and spacing
|
| 290 |
-
fig = plt.figure(figsize=(20, 24))
|
| 291 |
-
|
| 292 |
-
# Calculate height ratios for different plots
|
| 293 |
-
height_ratios = [1, 1, 1, 1, 1] # Equal height for all plots
|
| 294 |
-
gs = GridSpec(5, 1, figure=fig, height_ratios=height_ratios)
|
| 295 |
-
gs.update(hspace=0.4) # Increase vertical spacing between plots
|
| 296 |
-
|
| 297 |
-
# Temperature plot
|
| 298 |
-
ax1 = fig.add_subplot(gs[0])
|
| 299 |
-
ax1.plot(df['datetime'], df['temp'], label='Temperature', color='red')
|
| 300 |
-
ax1.plot(df['datetime'], df['wind_chill'], label='Wind Chill', color='blue')
|
| 301 |
-
ax1.set_title('Temperature and Wind Chill Over Time', pad=20)
|
| 302 |
-
ax1.set_xlabel('Date')
|
| 303 |
-
ax1.set_ylabel('Temperature (°F)')
|
| 304 |
-
ax1.legend()
|
| 305 |
-
ax1.grid(True)
|
| 306 |
-
ax1.tick_params(axis='x', rotation=45)
|
| 307 |
-
|
| 308 |
-
# Wind speed plot
|
| 309 |
-
ax2 = fig.add_subplot(gs[1])
|
| 310 |
-
ax2.plot(df['datetime'], df['wind_speed'], label='Wind Speed', color='blue')
|
| 311 |
-
ax2.plot(df['datetime'], df['wind_gust'], label='Wind Gust', color='orange')
|
| 312 |
-
ax2.set_title('Wind Speed and Gusts Over Time', pad=20)
|
| 313 |
-
ax2.set_xlabel('Date')
|
| 314 |
-
ax2.set_ylabel('Wind Speed (mph)')
|
| 315 |
-
ax2.legend()
|
| 316 |
-
ax2.grid(True)
|
| 317 |
-
ax2.tick_params(axis='x', rotation=45)
|
| 318 |
-
|
| 319 |
-
# Snow depth plot
|
| 320 |
-
ax3 = fig.add_subplot(gs[2])
|
| 321 |
-
ax3.plot(df['datetime'], df['snow_depth'], color='blue', label='Snow Depth')
|
| 322 |
-
ax3.set_title('Snow Depth Over Time', pad=20)
|
| 323 |
-
ax3.set_xlabel('Date')
|
| 324 |
-
ax3.set_ylabel('Snow Depth (inches)')
|
| 325 |
-
ax3.grid(True)
|
| 326 |
-
ax3.tick_params(axis='x', rotation=45)
|
| 327 |
-
|
| 328 |
-
# Daily new snow bar plot
|
| 329 |
-
ax4 = fig.add_subplot(gs[3])
|
| 330 |
-
snow_df = df[['datetime', 'snowfall_3hr']].copy()
|
| 331 |
-
snow_df['day_group'] = snow_df['datetime'].apply(
|
| 332 |
-
lambda x: x.date() if x.hour >= 9 else (x - pd.Timedelta(days=1)).date()
|
| 333 |
-
)
|
| 334 |
-
daily_snow = snow_df.groupby('day_group').apply(process_daily_snow).reset_index()
|
| 335 |
-
daily_snow.columns = ['date', 'new_snow']
|
| 336 |
-
|
| 337 |
-
ax4.bar(daily_snow['date'], daily_snow['new_snow'], color='blue')
|
| 338 |
-
ax4.set_title('Daily New Snow (Sum of 3-hour amounts, 9 AM Reset)', pad=20)
|
| 339 |
-
ax4.set_xlabel('Date')
|
| 340 |
-
ax4.set_ylabel('New Snow (inches)')
|
| 341 |
-
ax4.tick_params(axis='x', rotation=45)
|
| 342 |
-
ax4.grid(True, axis='y', linestyle='--', alpha=0.7)
|
| 343 |
-
|
| 344 |
-
# Add value labels on top of each bar
|
| 345 |
-
for i, v in enumerate(daily_snow['new_snow']):
|
| 346 |
-
if v > 0: # Only label bars with snow
|
| 347 |
-
ax4.text(i, v, f'{v:.1f}"', ha='center', va='bottom')
|
| 348 |
-
|
| 349 |
-
# SWE bar plot
|
| 350 |
-
ax5 = fig.add_subplot(gs[4])
|
| 351 |
-
daily_swe = df.groupby('date')['swe'].mean()
|
| 352 |
-
ax5.bar(daily_swe.index, daily_swe.values, color='lightblue')
|
| 353 |
-
ax5.set_title('Snow/Water Equivalent', pad=20)
|
| 354 |
-
ax5.set_xlabel('Date')
|
| 355 |
-
ax5.set_ylabel('SWE (inches)')
|
| 356 |
-
ax5.tick_params(axis='x', rotation=45)
|
| 357 |
-
|
| 358 |
-
# Adjust layout
|
| 359 |
-
plt.subplots_adjust(top=0.95, bottom=0.05, left=0.1, right=0.95)
|
| 360 |
-
|
| 361 |
-
# Create separate wind rose figure
|
| 362 |
-
fig_rose = plt.figure(figsize=(10, 10))
|
| 363 |
-
ax_rose = WindroseAxes.from_ax(fig=fig_rose)
|
| 364 |
-
create_wind_rose(df, ax_rose)
|
| 365 |
-
fig_rose.subplots_adjust(top=0.95, bottom=0.05, left=0.1, right=0.95)
|
| 366 |
-
|
| 367 |
-
return fig, fig_rose
|
| 368 |
-
|
| 369 |
def analyze_weather_data(site_id, hours):
|
| 370 |
"""Analyze weather data and create visualizations"""
|
| 371 |
try:
|
|
|
|
| 158 |
lambda x: x.date() if x.hour >= 9 else (x - pd.Timedelta(days=1)).date()
|
| 159 |
)
|
| 160 |
|
| 161 |
+
# Calculate daily snow totals
|
| 162 |
+
daily_totals = snow_df.groupby('day_group').apply(process_daily_snow)
|
| 163 |
+
|
| 164 |
+
return daily_totals.sum()
|
| 165 |
+
|
| 166 |
+
def process_daily_snow(group):
|
| 167 |
+
"""Sum up ONLY the 3-hour snowfall amounts for each day period"""
|
| 168 |
+
# Sort by time to ensure proper sequence
|
| 169 |
+
group = group.sort_values('datetime')
|
| 170 |
|
| 171 |
+
# Sum only the valid 3-hour amounts, treating NaN as 0
|
| 172 |
+
valid_amounts = group['snowfall_3hr'].fillna(0)
|
| 173 |
+
daily_total = valid_amounts.sum()
|
| 174 |
|
| 175 |
+
return daily_total
|
| 176 |
|
| 177 |
def create_plots(df):
|
| 178 |
"""Create all weather plots including SWE estimates"""
|
|
|
|
| 256 |
fig_rose.subplots_adjust(top=0.95, bottom=0.05, left=0.1, right=0.95)
|
| 257 |
|
| 258 |
return fig, fig_rose
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 259 |
|
| 260 |
def create_wind_rose(df, ax):
|
| 261 |
"""Create a wind rose plot"""
|
| 262 |
if not isinstance(ax, WindroseAxes):
|
| 263 |
ax = WindroseAxes.from_ax(ax=ax)
|
| 264 |
+
ax.bar(df['wind_dir_deg'].dropna(), df['wind_speed'].dropna(),
|
| 265 |
bins=np.arange(0, 40, 5), normed=True, opening=0.8, edgecolor='white')
|
| 266 |
ax.set_legend(title='Wind Speed (mph)')
|
| 267 |
ax.set_title('Wind Rose')
|
| 268 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 269 |
def analyze_weather_data(site_id, hours):
|
| 270 |
"""Analyze weather data and create visualizations"""
|
| 271 |
try:
|