You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.6 KiB
165 lines
4.6 KiB
# -*- coding: utf-8 -*-
|
|
|
|
import csv
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime
|
|
from typing import List
|
|
|
|
import cartopy.crs as ccrs
|
|
import matplotlib.pyplot as plt
|
|
import cartopy.feature as cfeature
|
|
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
|
from cartopy import geodesic
|
|
import shapely.geometry as sgeom
|
|
|
|
|
|
proj = ccrs.AlbersEqualArea(
|
|
central_longitude=-95,
|
|
central_latitude=35,
|
|
)
|
|
water_blue = "#7ebfd4"
|
|
|
|
|
|
def phys(name, resolv):
|
|
return cfeature.NaturalEarthFeature('physical', name, resolv, facecolor="none")
|
|
|
|
|
|
def cultural(name, resolv):
|
|
return cfeature.NaturalEarthFeature('cultural', name, resolv, facecolor="none")
|
|
|
|
|
|
land = phys("land", "50m")
|
|
rivers = phys("rivers_lake_centerlines", "50m")
|
|
lakes = phys("lakes", "50m")
|
|
countries = cultural("admin_0_countries", "50m")
|
|
states = cultural("admin_1_states_provinces_lines", "50m")
|
|
|
|
|
|
@dataclass
|
|
class Tornado:
|
|
om: str
|
|
yr: str
|
|
mo: str
|
|
dy: str
|
|
date: str
|
|
time: str
|
|
tz: str
|
|
st: str
|
|
stf: str
|
|
stn: str
|
|
mag: str
|
|
inj: str
|
|
fat: str
|
|
loss: str
|
|
closs: str
|
|
slat: str
|
|
slon: str
|
|
elat: str
|
|
elon: str
|
|
len: str
|
|
wid: str
|
|
ns: str
|
|
sn: str
|
|
sg: str
|
|
f1: str
|
|
f2: str
|
|
f3: str
|
|
f4: str
|
|
fc: str
|
|
|
|
def __post_init__(self):
|
|
self.id = int(self.om)
|
|
self.dt = datetime.strptime(self.date, "%Y-%m-%d")
|
|
self.slon = float(self.slon)
|
|
self.slat = float(self.slat)
|
|
self.elon = float(self.elon)
|
|
self.elat = float(self.elat)
|
|
self.mag = int(self.mag)
|
|
|
|
def __repr__(self):
|
|
return "<tornado {id} {date}>".format(id=self.id, date=self.dt)
|
|
|
|
|
|
def read_data():
|
|
tornados = []
|
|
with open("1950-2017_actual_tornadoes.csv", newline='') as csvfile:
|
|
reader = csv.DictReader(csvfile)
|
|
for i, row in enumerate(reader):
|
|
tornados.append(Tornado(**row))
|
|
return tornados
|
|
|
|
|
|
def draw_map(f_unknown, f_zero, f_one, f_two, f_three, f_four, f_five):
|
|
fig = plt.figure(frameon=False, figsize=(12, 7.1))
|
|
ax = fig.add_axes([0, 0, 1, 0.95], projection=proj)
|
|
ax.background_patch.set_facecolor(water_blue)
|
|
ax.set_extent([-122, -65, 21, 50], ccrs.Geodetic())
|
|
ax.add_feature(land, facecolor="#f0f0f0")
|
|
ax.add_feature(lakes, facecolor=water_blue)
|
|
ax.add_feature(countries, edgecolor="grey", linewidth=0.2, alpha=0.6, dashes='--')
|
|
ax.add_feature(states, edgecolor="grey", linewidth=0.2, alpha=0.4, dashes='--')
|
|
ax.coastlines(resolution='50m', color="#55aacc", linewidth=0.2)
|
|
|
|
geodetic = ccrs.Geodetic()
|
|
ax.plot(f_unknown.lons, f_unknown.lats, 'k', lw=0.2, alpha=0.7, label="Unknown", transform=geodetic)
|
|
ax.plot(f_zero.lons, f_zero.lats, '#ffbb00', lw=0.2, alpha=1, label="F0", transform=geodetic)
|
|
ax.plot(f_one.lons, f_one.lats, '#ff7700', lw=0.3, alpha=1, label="F1", transform=geodetic)
|
|
ax.plot(f_two.lons, f_two.lats, '#ff4400', lw=0.4, alpha=0.8, label="F2", transform=geodetic)
|
|
ax.plot(f_three.lons, f_three.lats, '#ff1100', lw=0.5, alpha=0.8, label="F3", transform=geodetic)
|
|
ax.plot(f_four.lons, f_four.lats, 'r', lw=0.6, alpha=0.8, label="F4", transform=geodetic)
|
|
ax.plot(f_five.lons, f_five.lats, 'r', lw=0.8, alpha=0.7, label="F5", transform=geodetic)
|
|
|
|
ax.axis('off')
|
|
|
|
plt.title(" US Tornados 1950-2017", loc='left')
|
|
ax.text(0, 0.01, " data from https://www.spc.noaa.gov/wcm/", transform=ax.transAxes, fontsize=6)
|
|
plt.legend(loc=4, title="Intensity", fontsize='small')
|
|
plt.savefig("tornados_us.png", dpi=190)
|
|
|
|
|
|
@dataclass
|
|
class Fmag:
|
|
lons: List[int] = field(default_factory=list)
|
|
lats: List[int] = field(default_factory=list)
|
|
|
|
|
|
def append(collection, tornado):
|
|
collection.lons.append(tornado.slon)
|
|
collection.lats.append(tornado.slat)
|
|
if tornado.elon < 0:
|
|
collection.lons.append(tornado.elon)
|
|
collection.lats.append(tornado.elat)
|
|
else:
|
|
collection.lons.append(tornado.slon)
|
|
collection.lats.append(tornado.slat)
|
|
collection.lons.append(None)
|
|
collection.lats.append(None)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
ts = read_data()
|
|
|
|
f_unknown = Fmag()
|
|
f_zero = Fmag()
|
|
f_one = Fmag()
|
|
f_two = Fmag()
|
|
f_three = Fmag()
|
|
f_four = Fmag()
|
|
f_five = Fmag()
|
|
for t in ts:
|
|
if t.mag == 0:
|
|
append(f_zero, t)
|
|
elif t.mag == 1:
|
|
append(f_one, t)
|
|
elif t.mag == 2:
|
|
append(f_two, t)
|
|
elif t.mag == 3:
|
|
append(f_three, t)
|
|
elif t.mag == 4:
|
|
append(f_four, t)
|
|
elif t.mag == 5:
|
|
append(f_five, t)
|
|
else:
|
|
append(f_unknown, t)
|
|
|
|
draw_map(f_unknown, f_zero, f_one, f_two, f_three, f_four, f_five)
|