nakas commited on
Commit
63aab61
·
verified ·
1 Parent(s): ed69731

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -81
app.py CHANGED
@@ -6,94 +6,155 @@ import numpy as np
6
  from datetime import datetime, timedelta
7
  import matplotlib.pyplot as plt
8
  from matplotlib.gridspec import GridSpec
 
9
 
10
- # Set the style for all plots
11
- plt.style.use('seaborn-v0_8-darkgrid')
12
- plt.rcParams['figure.figsize'] = [12, 8]
13
- plt.rcParams['figure.dpi'] = 100
14
- plt.rcParams['font.size'] = 10
15
- plt.rcParams['axes.labelsize'] = 12
16
- plt.rcParams['axes.titlesize'] = 14
17
-
18
- def get_weather_data(station_id, hours=72):
19
  """
20
- Fetch weather data from NWS API
21
  """
 
 
 
 
 
 
 
22
  headers = {
23
  'User-Agent': '(Weather Data Viewer, contact@yourdomain.com)',
24
  'Accept': 'application/json'
25
  }
26
 
 
 
 
 
 
27
  try:
28
- # First get latest observation to see format
29
- latest_url = f'https://api.weather.gov/stations/{station_id}/observations/latest'
30
- response = requests.get(latest_url, headers=headers)
31
- response.raise_for_status()
32
- latest = response.json()
33
- print("Latest observation data structure:")
34
- print(latest)
35
-
36
- # Get historical observations
37
- observations_url = f'https://api.weather.gov/stations/{station_id}/observations'
38
- params = {
39
- 'limit': hours,
40
- 'start': (datetime.utcnow() - timedelta(hours=hours)).isoformat() + 'Z'
41
- }
42
-
43
- response = requests.get(observations_url, headers=headers, params=params)
44
- response.raise_for_status()
45
- data = response.json()
46
 
47
- records = []
48
- for obs in data['features']:
49
- props = obs['properties']
50
-
51
- # Print the first observation's full structure
52
- if len(records) == 0:
53
- print("\nFirst observation properties:")
54
- print(props)
55
-
56
- record = {
57
- 'timestamp': props['timestamp'],
58
- 'temperature': props.get('temperature', {}).get('value'),
59
- 'relative_humidity': props.get('relativeHumidity', {}).get('value'),
60
- 'wind_speed': props.get('windSpeed', {}).get('value'),
61
- 'wind_direction': props.get('windDirection', {}).get('value'),
62
- 'barometric_pressure': props.get('barometricPressure', {}).get('value'),
63
- 'snow_depth': props.get('snowDepth', {}).get('value'),
64
- 'snow_accumulation': props.get('snowfall', {}).get('value', 0)
65
- }
66
- records.append(record)
67
 
68
- df = pd.DataFrame(records)
69
- df['timestamp'] = pd.to_datetime(df['timestamp'])
70
- df['date'] = df['timestamp'].dt.date
71
-
72
- # Convert units to imperial
73
- df['temperature'] = (df['temperature'] * 9/5) + 32 # C to F
74
- df['wind_speed'] = df['wind_speed'] * 2.237 # m/s to mph
75
-
76
- # Handle snow depth
77
- print("\nRaw snow depth values:")
78
- print(df['snow_depth'].unique())
79
-
80
- # If snow depth is in meters, convert to inches
81
- if df['snow_depth'].notna().any():
82
- df['snow_depth'] = df['snow_depth'] * 39.3701 # meters to inches
83
-
84
- # Forward fill missing snow depth values
85
- df['snow_depth'] = df['snow_depth'].ffill()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
 
87
- # Calculate cumulative snow accumulation
88
- df['cumulative_snow'] = df['snow_accumulation'].fillna(0).cumsum()
 
89
 
90
- print("\nProcessed snow depth values (inches):")
91
- print(df['snow_depth'].unique())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
93
  return df, None
94
-
95
- except requests.exceptions.RequestException as e:
96
- return None, f"Error fetching data: {str(e)}"
97
 
98
  def create_wind_rose(ax, data, title):
99
  """
@@ -157,7 +218,6 @@ def create_visualizations(df):
157
  ax1 = fig.add_subplot(gs[0, :])
158
  ax2 = fig.add_subplot(gs[1, :])
159
  ax3 = fig.add_subplot(gs[2, :])
160
- ax4 = fig.add_subplot(gs[3, :])
161
 
162
  if not df['temperature'].isna().all():
163
  ax1.plot(df['timestamp'], df['temperature'], linewidth=2)
@@ -182,13 +242,7 @@ def create_visualizations(df):
182
  ax3.set_xlabel('')
183
  ax3.grid(True)
184
 
185
- if not df['cumulative_snow'].isna().all():
186
- ax4.plot(df['timestamp'], df['cumulative_snow'], linewidth=2)
187
- ax4.set_title('Cumulative Snow Accumulation')
188
- ax4.set_ylabel('Snow Accumulation (inches)')
189
- ax4.grid(True)
190
-
191
- for ax in [ax1, ax2, ax3, ax4]:
192
  ax.tick_params(axis='x', rotation=45)
193
  ax.xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%Y-%m-%d %H:%M'))
194
 
 
6
  from datetime import datetime, timedelta
7
  import matplotlib.pyplot as plt
8
  from matplotlib.gridspec import GridSpec
9
+ import json
10
 
11
+ def get_raw_data(station_id):
 
 
 
 
 
 
 
 
12
  """
13
+ Get raw data from multiple endpoints to find snow depth data
14
  """
15
+ # Try standard observations endpoint
16
+ url1 = f"https://api.weather.gov/stations/{station_id}/observations"
17
+ # Try station metadata endpoint
18
+ url2 = f"https://api.weather.gov/stations/{station_id}"
19
+ # Try grid point data endpoint (need to get grid coordinates first)
20
+ url3 = f"https://api.weather.gov/points/{station_id}"
21
+
22
  headers = {
23
  'User-Agent': '(Weather Data Viewer, contact@yourdomain.com)',
24
  'Accept': 'application/json'
25
  }
26
 
27
+ params = {
28
+ 'limit': 720, # Get maximum available data
29
+ 'start': (datetime.utcnow() - timedelta(hours=720)).isoformat() + 'Z'
30
+ }
31
+
32
  try:
33
+ # Get standard observations
34
+ print("\nTrying standard observations endpoint...")
35
+ response1 = requests.get(url1, headers=headers, params=params)
36
+ response1.raise_for_status()
37
+ data1 = response1.json()
38
+ print("Sample observation data:")
39
+ if 'features' in data1 and len(data1['features']) > 0:
40
+ print(json.dumps(data1['features'][0]['properties'], indent=2))
 
 
 
 
 
 
 
 
 
 
41
 
42
+ # Get station metadata
43
+ print("\nTrying station metadata endpoint...")
44
+ response2 = requests.get(url2, headers=headers)
45
+ response2.raise_for_status()
46
+ data2 = response2.json()
47
+ print("Station metadata:")
48
+ print(json.dumps(data2, indent=2))
49
+
50
+ # Try to get grid point data
51
+ print("\nTrying grid point endpoint...")
52
+ response3 = requests.get(url3, headers=headers)
53
+ if response3.status_code == 200:
54
+ data3 = response3.json()
55
+ print("Grid point data:")
56
+ print(json.dumps(data3, indent=2))
 
 
 
 
 
57
 
58
+ # If we got grid data, try to get forecast data
59
+ if 'properties' in data3:
60
+ grid_id = data3['properties'].get('gridId')
61
+ grid_x = data3['properties'].get('gridX')
62
+ grid_y = data3['properties'].get('gridY')
63
+ if all([grid_id, grid_x, grid_y]):
64
+ forecast_url = f"https://api.weather.gov/gridpoints/{grid_id}/{grid_x},{grid_y}"
65
+ print(f"\nTrying forecast endpoint: {forecast_url}")
66
+ response4 = requests.get(forecast_url, headers=headers)
67
+ if response4.status_code == 200:
68
+ data4 = response4.json()
69
+ print("Forecast data:")
70
+ print(json.dumps(data4.get('properties', {}), indent=2))
71
+
72
+ # Return standard observations for now
73
+ return data1
74
+ except Exception as e:
75
+ print(f"Error fetching data: {e}")
76
+ print("Full error details:")
77
+ import traceback
78
+ traceback.print_exc()
79
+ return None
80
+
81
+ def parse_raw_data(data):
82
+ """
83
+ Parse the raw JSON data into a DataFrame
84
+ """
85
+ if not data or 'features' not in data:
86
+ return None
87
+
88
+ records = []
89
+ for feature in data['features']:
90
+ props = feature['properties']
91
 
92
+ # Getting raw message which might contain snow depth info
93
+ raw_message = props.get('rawMessage', '')
94
+ print(f"Raw message: {raw_message}")
95
 
96
+ # Try to parse snow depth from raw message or use NaN
97
+ snow_depth = None
98
+
99
+ record = {
100
+ 'timestamp': props['timestamp'],
101
+ 'temperature': props.get('temperature', {}).get('value'),
102
+ 'wind_speed': props.get('windSpeed', {}).get('value'),
103
+ 'wind_direction': props.get('windDirection', {}).get('value'),
104
+ 'snow_depth': snow_depth,
105
+ 'raw_message': raw_message # Store raw message for debugging
106
+ }
107
+ records.append(record)
108
+
109
+ df = pd.DataFrame(records)
110
+ return df
111
+
112
+ def process_weather_data(df):
113
+ """
114
+ Process the weather DataFrame
115
+ """
116
+ if df is None or df.empty:
117
+ return None
118
+
119
+ # Convert timestamp
120
+ df['timestamp'] = pd.to_datetime(df['timestamp'])
121
+ df['date'] = df['timestamp'].dt.date
122
+
123
+ # Convert temperature from C to F
124
+ df['temperature'] = (df['temperature'] * 9/5) + 32
125
+
126
+ # Convert wind speed from m/s to mph
127
+ df['wind_speed'] = df['wind_speed'] * 2.237
128
+
129
+ return df
130
+
131
+ def get_weather_data(station_id, hours=72):
132
+ """
133
+ Main function to get and process weather data
134
+ """
135
+ try:
136
+ # Get raw data
137
+ raw_data = get_raw_data(station_id)
138
+ if raw_data is None:
139
+ return None, "Failed to fetch data"
140
+
141
+ # Parse raw data
142
+ df = parse_raw_data(raw_data)
143
+ if df is None:
144
+ return None, "Failed to parse data"
145
+
146
+ # Process data
147
+ df = process_weather_data(df)
148
+ if df is None:
149
+ return None, "Failed to process data"
150
+
151
+ print("\nSample of processed data:")
152
+ print(df.head())
153
 
154
  return df, None
155
+
156
+ except Exception as e:
157
+ return None, f"Error: {str(e)}"
158
 
159
  def create_wind_rose(ax, data, title):
160
  """
 
218
  ax1 = fig.add_subplot(gs[0, :])
219
  ax2 = fig.add_subplot(gs[1, :])
220
  ax3 = fig.add_subplot(gs[2, :])
 
221
 
222
  if not df['temperature'].isna().all():
223
  ax1.plot(df['timestamp'], df['temperature'], linewidth=2)
 
242
  ax3.set_xlabel('')
243
  ax3.grid(True)
244
 
245
+ for ax in [ax1, ax2, ax3]:
 
 
 
 
 
 
246
  ax.tick_params(axis='x', rotation=45)
247
  ax.xaxis.set_major_formatter(plt.matplotlib.dates.DateFormatter('%Y-%m-%d %H:%M'))
248