Skip to content
This repository was archived by the owner on Jan 9, 2020. It is now read-only.

Commit 57ddbbb

Browse files
author
Aodhan Sweeney
committed
Adding spc Tracker and the hurricane tracker with small updates.
1 parent 528750d commit 57ddbbb

File tree

2 files changed

+174
-16
lines changed

2 files changed

+174
-16
lines changed

examples/HurricaneTracker.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
66
This GUI takes data pulled from the National
77
Hurricane Center and plots specific storms and
8-
their tracks. The GUI runs using ipwidgets, and
9-
is intended to be used as an ipython notebook.
8+
their tracks. The GUI runs using ipywidgets, and
9+
is intended to be used as an Jupyter notebook.
1010
"""
1111

1212
import cartopy.crs as ccrs
13+
from IPython.display import display
1314
import ipywidgets as widgets
1415
import matplotlib.pyplot as plt
1516
import numpy as np
16-
from pandas import DataFrame
1717
from siphon.simplewebservice import nhc
1818

19+
1920
class NHC_GUI:
2021
"""
2122
Graphic User Interface designed to allow users to access National Hurricane Center data.
@@ -45,7 +46,6 @@ def __init__(self):
4546
tooltip='Description')
4647
widgets.interact(self.get_track, track_button=self.track_button)
4748

48-
4949
def get_storms_slider(self, year_slider):
5050
"""
5151
Take a year chosen by the user, and create a list of all storms during that year.
@@ -77,7 +77,7 @@ def get_name_dropdown(self, storm_names):
7777
if self.filename.empty is False:
7878
self.filename = file_name[0]
7979
elif self.filename.empty is True:
80-
raise Exception('ValueError: No file name data for this year.')
80+
raise ValueError('No data for specific file name of the chosen.')
8181

8282
def get_track(self, track_button):
8383
"""
@@ -109,10 +109,10 @@ def get_models(self, models):
109109
self.NHCD.model_selection_latlon(models)
110110
self.date_times = self.NHCD.date_times.tolist()
111111
self.plot_slider = widgets.IntSlider(min=0, max=(len(self.date_times)-1),
112-
value=0, description='Tracks Time',
113-
disabled=False)
112+
value=0, description='Tracks Time',
113+
disabled=False)
114114
self.play = widgets.Play(interval=800, min=0, max=(len(self.date_times)-1),
115-
value=0, description='Tracks Time')
115+
value=0, description='Tracks Time')
116116
widgets.jslink((self.plot_slider, 'value'), (self.play, 'value'))
117117
self.box = widgets.HBox([self.plot_slider, self.play])
118118
display(self.plot_slider)
@@ -144,8 +144,7 @@ def plotting(self, plot_slider):
144144
min_best_lon = min(self.best_lons)
145145
max_best_lon = max(self.best_lons)
146146

147-
148-
#Plotting the tracks on top of a cartopy stock image projection
147+
# Plotting the tracks on top of a cartopy stock image projection
149148
self.fig = plt.figure(figsize=(14, 11))
150149
self.ax = self.fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
151150
self.ax.stock_img()
@@ -156,8 +155,6 @@ def plotting(self, plot_slider):
156155
self.ax.set_extent([(min_best_lon - 40), (max_best_lon + 40),
157156
(min_best_lat - 40), (max_best_lat + 40)])
158157

159-
160-
161158
jet = plt.get_cmap('jet')
162159
colors = iter(jet(np.linspace(0.2, 1, (len(self.model_select.value)+1))))
163160
left = .1
@@ -166,16 +163,17 @@ def plotting(self, plot_slider):
166163
fontsize=14, color='black')
167164

168165
for model_type in self.NHCD.model_table:
169-
one_model_time = model_type[model_type['WarnDT'] == self.date_times[plot_slider]]
170-
lats = one_model_time['Lat'].tolist()
171-
lons = one_model_time['Lon'].tolist()
166+
one_time = model_type[model_type['WarnDT'] == self.date_times[plot_slider]]
167+
lats = one_time['Lat'].tolist()
168+
lons = one_time['Lon'].tolist()
172169
if len(lats) != 0:
173170
model_list = model_type['Model'].tolist()
174171
self.ax.plot(lons, lats, marker='o', color=next(colors),
175172
label=model_list[0])
176173
plt.title('Storm Name: {0} Year: {1}'.format(self.storm_names.value,
177-
self.year))
174+
self.year))
178175
plt.legend()
179176

177+
180178
######################################################################
181179
NHC_GUI()

examples/SPCTracker.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""
2+
GUI for Storm Prediction Center
3+
===============================
4+
5+
This GUI takes in SPC data and plots
6+
all events from a day. It is meant
7+
to show the ease of data access and
8+
creation of a useful plot using the
9+
Siphon Simple Web Service for the SPC.
10+
"""
11+
12+
13+
import cartopy.crs as ccrs
14+
import cartopy.feature as cfeature
15+
from IPython.display import display
16+
import ipywidgets as widgets
17+
import matplotlib.patches as mpatches
18+
import matplotlib.pyplot as plt
19+
import pandas as pd
20+
from siphon.simplewebservice import spc
21+
22+
23+
class SPC_GUI:
24+
"""
25+
Graphic User Interface designed to allow users to access Storm Prediction Center data.
26+
27+
This class uses ipython widgets. NOTE: date chosen must be from 2011 to present because
28+
methods of data parsing are different and will not work for dates earlier.
29+
"""
30+
def __init__(self):
31+
"""
32+
Create object that references SPC.py and thus the Storm Prediction Center.
33+
34+
This initiation creates the SPC object and also creates a widget that allows
35+
the user to select a date for which to animate SPC reports from the years of
36+
2011 and onward.
37+
"""
38+
self.datepicker = widgets.DatePicker(description='Pick a Date:', disabled=False)
39+
widgets.interact(self.format_date, datepicker=self.datepicker)
40+
41+
def format_date(self, datepicker):
42+
"""
43+
Allow user to chose a date for which to plot the SPC events.
44+
45+
Parameters
46+
==========
47+
datepicker: ipywidget
48+
allows chosing of date
49+
"""
50+
if datepicker is not None:
51+
year_string = datepicker.strftime('%Y')
52+
month_string = datepicker.strftime('%m')
53+
day_string = datepicker.strftime('%d')
54+
self.date_string = year_string + month_string + day_string
55+
self.stormpicker = widgets.SelectMultiple(options=['tornado', 'hail', 'wind'],
56+
description='Event Type: ')
57+
widgets.interact(self.fetch_spc, stormpicker=self.stormpicker)
58+
59+
def fetch_spc(self, stormpicker):
60+
"""
61+
Use a date chosen by the user and create widgets that allow you to iterate through
62+
the pandas dataframe holding the data.
63+
64+
Parameters
65+
==========
66+
stormpicker: ipywidget
67+
allows choice of the storm type to be plotted
68+
"""
69+
self.spc_data_table = []
70+
for storm_type in stormpicker:
71+
one_storm_type = spc.SPCD(storm_type, self.date_string)
72+
# Storm must be after year 2011
73+
if int(self.date_string[:4]) < 2011:
74+
raise ValueError('SPC GUI does not support events before 2012.')
75+
self.spc_data_table.append(one_storm_type.day_table)
76+
77+
if self.spc_data_table != []:
78+
self.plot_button = widgets.ToggleButton(value=False, description='Plot SPC Events',
79+
disabled=False, button_style='danger',
80+
tooltip='Description')
81+
82+
self.all_events = pd.concat(self.spc_data_table, sort=False)
83+
self.all_events = self.all_events.sort_index()
84+
85+
if self.all_events.empty:
86+
raise ValueError('No storm reports of any type for this date.')
87+
88+
self.plot_slider = widgets.IntSlider(min=0, max=(len(self.all_events)-1),
89+
value=0, description='Event #',
90+
disabled=False)
91+
self.play = widgets.Play(interval=900, min=0, max=(len(self.all_events)-1),
92+
value=0, description='Event #')
93+
widgets.jslink((self.plot_slider, 'value'), (self.play, 'value'))
94+
self.plot_button = widgets.ToggleButton(value=False,
95+
description='Plot SPC Events',
96+
disabled=False, button_style='danger',
97+
tooltip='description')
98+
self.box = widgets.HBox([self.plot_slider, self.play])
99+
display(self.plot_slider)
100+
widgets.interact(self.plot_events, plot_slider=self.play,
101+
plot_button=self.plot_button)
102+
103+
def plot_events(self, plot_slider, plot_button):
104+
"""
105+
Plot the storm events chosen for the date picked by the user and the type of storms
106+
selected.
107+
108+
Parameters
109+
==========
110+
plot_sider: ipywidget
111+
pases a iteration of the dataframe holding all storm data to be plotted
112+
113+
plot_button: ipywidget
114+
toggle button that when activated allows for plotting
115+
"""
116+
spc_event = self.all_events.iloc[plot_slider]
117+
if self.plot_button.value is True:
118+
trimmed_event = spc_event.dropna()
119+
# Plotting the tracks on top of a cartopy stock image projection
120+
self.fig = plt.figure(figsize=(14, 11))
121+
self.ax = self.fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
122+
self.ax.stock_img()
123+
state_lines = 'admin_1_states_provinces_lines'
124+
states_provinces = cfeature.NaturalEarthFeature(category='cultural',
125+
name=state_lines,
126+
scale='50m',
127+
facecolor='none')
128+
self.ax.add_feature(cfeature.BORDERS)
129+
self.ax.add_feature(cfeature.COASTLINE)
130+
self.ax.add_feature(cfeature.LAKES)
131+
132+
self.ax.add_feature(states_provinces, edgecolor='gray')
133+
self.ax.set_title('SPC Events for {}/{}/{}'.format(self.date_string[4:6],
134+
self.date_string[6:8],
135+
self.date_string[0:4]))
136+
self.data_projection = ccrs.PlateCarree()
137+
if 'Size (in)' in trimmed_event:
138+
self.ax.plot(spc_event['Lon'], spc_event['Lat'], marker='o', color='blue',
139+
label='Hail', transform=self.data_projection, markersize=7)
140+
if 'Speed (kt)' in trimmed_event:
141+
self.ax.plot(spc_event['Lon'], spc_event['Lat'], marker='o', color='green',
142+
label='Wind', transform=self.data_projection, markersize=7)
143+
if 'F-Scale' in trimmed_event:
144+
self.ax.plot(spc_event['Lon'], spc_event['Lat'], marker='o', color='red',
145+
label='Tornado', transform=self.data_projection, markersize=7)
146+
self.ax.set_extent([-60, -130, 23, 50])
147+
hail_event = mpatches.Patch(color='blue', label='Hail')
148+
wind_event = mpatches.Patch(color='green', label='Wind')
149+
torn_event = mpatches.Patch(color='red', label='Tornado')
150+
self.ax.legend(handles=[hail_event, wind_event, torn_event])
151+
comment = spc_event['Comment']
152+
if len(comment) > 70:
153+
comment = comment[:70] + '\n' + comment[70:]
154+
if len(comment) > 140:
155+
comment = comment[:140] + '\n' + comment[140:]
156+
self.fig.text(0.15, 0.2, comment, fontsize=15)
157+
158+
159+
######################################################################
160+
SPC_GUI()

0 commit comments

Comments
 (0)