Map of tornado historic tornado traces
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.

115 lines
2.8 KiB

  1. # -*- coding: utf-8 -*-
  2. import csv
  3. from dataclasses import dataclass
  4. from datetime import datetime
  5. import cartopy.crs as ccrs
  6. import matplotlib.pyplot as plt
  7. import cartopy.feature as cfeature
  8. from mpl_toolkits.axes_grid1.inset_locator import inset_axes
  9. from cartopy import geodesic
  10. import shapely.geometry as sgeom
  11. proj = ccrs.AlbersEqualArea(
  12. central_longitude=-95,
  13. central_latitude=40,
  14. )
  15. water_blue = "#7ebfd4"
  16. def phys(name, resolv):
  17. return cfeature.NaturalEarthFeature('physical', name, resolv, facecolor="none")
  18. def cultural(name, resolv):
  19. return cfeature.NaturalEarthFeature('cultural', name, resolv, facecolor="none")
  20. land = phys("land", "50m")
  21. rivers = phys("rivers_lake_centerlines", "50m")
  22. lakes = phys("lakes", "50m")
  23. countries = cultural("admin_0_countries", "50m")
  24. states = cultural("admin_1_states_provinces_lines", "50m")
  25. @dataclass
  26. class Tornado:
  27. om: str
  28. yr: str
  29. mo: str
  30. dy: str
  31. date: str
  32. time: str
  33. tz: str
  34. st: str
  35. stf: str
  36. stn: str
  37. mag: str
  38. inj: str
  39. fat: str
  40. loss: str
  41. closs: str
  42. slat: str
  43. slon: str
  44. elat: str
  45. elon: str
  46. len: str
  47. wid: str
  48. ns: str
  49. sn: str
  50. sg: str
  51. f1: str
  52. f2: str
  53. f3: str
  54. f4: str
  55. fc: str
  56. def __post_init__(self):
  57. self.id = int(self.om)
  58. self.dt = datetime.strptime(self.date, "%Y-%m-%d")
  59. self.slon = float(self.slon)
  60. self.slat = float(self.slat)
  61. self.elon = float(self.elon)
  62. self.elat = float(self.elat)
  63. def __repr__(self):
  64. return "<tornado {id} {date}>".format(id=self.id, date=self.dt)
  65. def read_data():
  66. tornados = []
  67. with open("1950-2017_actual_tornadoes.csv", newline='') as csvfile:
  68. reader = csv.DictReader(csvfile)
  69. for i, row in enumerate(reader):
  70. tornados.append(Tornado(**row))
  71. return tornados
  72. def draw_map(data):
  73. fig = plt.figure(frameon=False)
  74. ax = fig.add_subplot(111, projection=proj)
  75. ax.background_patch.set_facecolor(water_blue)
  76. ax.set_extent([-125, -65, 20, 50], ccrs.Geodetic())
  77. ax.add_feature(land, facecolor="#f0f0f0")
  78. ax.add_feature(rivers, edgecolor=water_blue)
  79. ax.add_feature(lakes, facecolor=water_blue)
  80. ax.add_feature(countries, edgecolor="grey", linewidth=0.2, alpha=0.6, dashes='--')
  81. ax.add_feature(states, edgecolor="grey", linewidth=0.2, alpha=0.4, dashes='--')
  82. for i, t in enumerate(data):
  83. print(i)
  84. if t.elon < 0:
  85. ax.plot([t.slon, t.elon], [t.slat, t.elat], 'r', lw=0.3, transform=ccrs.Geodetic())
  86. else:
  87. ax.plot([t.slon, t.slon], [t.slat, t.slat], 'r', lw=0.3, transform=ccrs.Geodetic())
  88. fig.tight_layout()
  89. plt.savefig("tornados_us.png", dpi=320)
  90. if __name__ == '__main__':
  91. ts = read_data()
  92. draw_map(ts)