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

Commit 7f82467

Browse files
author
Aodhan Sweeney
committed
Adding spc Tracker
1 parent 528750d commit 7f82467

File tree

1 file changed

+159
-0
lines changed

1 file changed

+159
-0
lines changed

examples/SPCTracker.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
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+
from datetime import datetime
14+
15+
import cartopy.feature as cfeature
16+
import cartopy.crs as ccrs
17+
import ipywidgets as widgets
18+
import matplotlib.pyplot as plt
19+
import matplotlib.patches as mpatches
20+
import numpy as np
21+
import pandas as pd
22+
import math as m
23+
from siphon.simplewebservice import spc
24+
25+
26+
class SPC_GUI:
27+
"""
28+
Graphic User Interface designed to allow users to access Storm Prediction Center data.
29+
30+
This class uses ipython widgets. NOTE: storm chosen must be after 2011 because methods
31+
of data parsing are different and will not work for dates earlier.
32+
"""
33+
def __init__(self):
34+
"""
35+
Create object that references SPC.py and thus the Storm Prediction Center.
36+
37+
This initiation creates the SPC object and also creates a widget that allows
38+
the user to select a date for which to animate SPC reports from the years of
39+
2011 and onward.
40+
"""
41+
self.datepicker = widgets.DatePicker(description='Pick a Date:', disabled=False)
42+
widgets.interact(self.format_date, datepicker=self.datepicker)
43+
44+
def format_date(self, datepicker):
45+
"""
46+
Allow user to chose a date for which to plot the SPC events.
47+
48+
Parameters
49+
==========
50+
datepicker: ipywidget
51+
allows chosing of date
52+
"""
53+
if datepicker != None:
54+
year_string = datepicker.strftime('%Y')
55+
month_string = datepicker.strftime('%m')
56+
day_string = datepicker.strftime('%d')
57+
self.date_string = year_string + month_string + day_string
58+
self.stormpicker = widgets.SelectMultiple(options=['tornado', 'hail', 'wind'],
59+
description='Event Type: ')
60+
widgets.interact(self.fetch_spc, stormpicker=self.stormpicker)
61+
62+
def fetch_spc(self, stormpicker):
63+
"""
64+
Use a date chosen by the user and create widgets that allow you to iterate through
65+
the pandas dataframe holding the data.
66+
67+
Parameters
68+
==========
69+
stormpicker: ipywidget
70+
allows choice of the storm type to be plotted
71+
"""
72+
self.spc_data_table = []
73+
for storm_type in stormpicker:
74+
one_storm_type = spc.SPCD(storm_type, self.date_string)
75+
# Storm must be after year 2011
76+
if int(self.date_string[:4]) < 2011:
77+
one_storm_type = one_storm_type.day_table[['Time','Start Lat', 'Start Lon']]
78+
self.spc_data_table.append(one_storm_type.day_table)
79+
80+
if self.spc_data_table != []:
81+
self.plot_button = widgets.ToggleButton(value=False, description='Plot SPC Events',
82+
disabled=False, button_style='danger',
83+
tooltip='Description')
84+
85+
self.all_events = pd.concat(self.spc_data_table, sort=False)
86+
self.all_events = self.all_events.sort_index()
87+
88+
if self.all_events.empty:
89+
raise Exception('Value Error: Can\'t plot a storm event that doesn\'t exist.')
90+
91+
self.plot_slider = widgets.IntSlider(min=0, max=(len(self.all_events)-1),
92+
value=0, description='Event #',
93+
disabled=False)
94+
self.play = widgets.Play(interval=500, min=0, max=(len(self.all_events)-1),
95+
value=0, description='Event #')
96+
widgets.jslink((self.plot_slider, 'value'), (self.play, 'value'))
97+
self.plot_button = widgets.ToggleButton(value=False, description='Plot SPC Events',
98+
disabled=False, button_style='danger',
99+
tooltip='description')
100+
self.box = widgets.HBox([self.plot_slider, self.play])
101+
display(self.plot_slider)
102+
widgets.interact(self.plot_events, plot_slider=self.play, plot_button=self.plot_button)
103+
104+
def plot_events(self, plot_slider, plot_button):
105+
"""
106+
Plot the storm events chosen for the date picked by the user and the type of storms
107+
selected.
108+
109+
Parameters
110+
==========
111+
plot_sider: ipywidget
112+
pases a iteration of the dataframe holding all storm data to be plotted
113+
114+
plot_button: ipywidget
115+
toggle button that when activated allows for plotting
116+
"""
117+
spc_event = self.all_events.iloc[plot_slider]
118+
if self.plot_button.value == True:
119+
trimmed_event = spc_event.dropna()
120+
#Plotting the tracks on top of a cartopy stock image projection
121+
self.fig = plt.figure(figsize=(14, 11))
122+
self.ax = self.fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
123+
self.ax.stock_img()
124+
states_provinces = cfeature.NaturalEarthFeature(category='cultural',
125+
name='admin_1_states_provinces_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+
SPC_GUI()

0 commit comments

Comments
 (0)