# https://www.ncdc.noaa.gov/ibtracs/index.php?name=ib-v4-access
import sys
import matplotlib.pyplot as plt
from matplotlib import gridspec
import numpy as np
from scipy import stats
import csv
from datetime import date
from datetime import datetime
from elevations import Elevations
from math import sin, cos, sqrt, atan2, radians

PRINT = False

BASINTITLE = "ATLANTIC"
FILENAME = "ibtracs.NA.list.v04r00.csv"

DECREASES = [{'name': 'ABLE', 'year': 1950, 'dec': -35}, {'name': 'DOG', 'year': 1950, 'dec': -35}, {'name': 'FOX', 'year': 1950, 'dec': -35}, {'name': 'EASY', 'year': 1951, 'dec': -30}, {'name': 'BETSY', 'year': 1956, 'dec': -30}, {'name': 'CARRIE', 'year': 1957, 'dec': -35}, {'name': 'ILSA', 'year': 1958, 'dec': -30}, {'name': 'ETHEL', 'year': 1960, 'dec': -30}, {'name': 'ESTHER', 'year': 1961, 'dec': -30}, {'name': 'FRANCES', 'year': 1961, 'dec': -35}, {'name': 'ARLENE', 'year': 1963, 'dec': -35}, {'name': 'BEULAH', 'year': 1963, 'dec': -30}, {'name': 'ALMA', 'year': 1966, 'dec': -30}, {'name': 'INEZ', 'year': 1966, 'dec': -50}, {'name': 'BEULAH', 'year': 1967, 'dec': -55}, {'name': 'GLADYS', 'year': 1975, 'dec': -35}, {'name': 'FRANCES', 'year': 1976, 'dec': -30}, {'name': 'ELLA', 'year': 1978, 'dec': -55}, {'name': 'ALLEN', 'year': 1980, 'dec': -55}, {'name': 'HARVEY', 'year': 1981, 'dec': -35}, {'name': 'DEBBY', 'year': 1982, 'dec': -40}, {'name': 'DIANA', 'year': 1984, 'dec': -30}, {'name': 'GLORIA', 'year': 1985, 'dec': -45}, {'name': 'JOAN:MIRIAM', 'year': 1988, 'dec': -40}, {'name': 'CLAUDETTE', 'year': 1991, 'dec': -30}, {'name': 'EDOUARD', 'year': 1996, 'dec': -30}, {'name': 'HORTENSE', 'year': 1996, 'dec': -30}, {'name': 'GEORGES', 'year': 1998, 'dec': -35}, {'name': 'MITCH', 'year': 1998, 'dec': -55}, {'name': 'CINDY', 'year': 1999, 'dec': -30}, {'name': 'FLOYD', 'year': 1999, 'dec': -30}, {'name': 'LENNY', 'year': 1999, 'dec': -50}, {'name': 'ALBERTO', 'year': 2000, 'dec': -40}, {'name': 'ISAAC', 'year': 2000, 'dec': -30}, {'name': 'KEITH', 'year': 2000, 'dec': -45}, {'name': 'LILI', 'year': 2002, 'dec': -30}, {'name': 'ALEX', 'year': 2004, 'dec': -40}, {'name': 'KARL', 'year': 2004, 'dec': -35}, {'name': 'KATRINA', 'year': 2005, 'dec': -35}, {'name': 'MARIA', 'year': 2005, 'dec': -35}, {'name': 'RITA', 'year': 2005, 'dec': -40}, {'name': 'WILMA', 'year': 2005, 'dec': -30}, {'name': 'FELIX', 'year': 2007, 'dec': -35}, {'name': 'BERTHA', 'year': 2008, 'dec': -40}, {'name': 'OMAR', 'year': 2008, 'dec': -45}, {'name': 'EARL', 'year': 2010, 'dec': -40}, {'name': 'JULIA', 'year': 2010, 'dec': -35}, {'name': 'KATIA', 'year': 2011, 'dec': -35}, {'name': 'OPHELIA', 'year': 2011, 'dec': -50}, {'name': 'RINA', 'year': 2011, 'dec': -35}, {'name': 'SANDY', 'year': 2012, 'dec': -30}, {'name': 'DANNY', 'year': 2015, 'dec': -40}, {'name': 'JOAQUIN', 'year': 2015, 'dec': -45}, {'name': 'MATTHEW', 'year': 2016, 'dec': -30}, {'name': 'NICOLE', 'year': 2016, 'dec': -45}, {'name': 'JOSE', 'year': 2017, 'dec': -30}, {'name': 'FLORENCE', 'year': 2018, 'dec': -40}, {'name': 'DORIAN', 'year': 2019, 'dec': -40}, {'name': 'HUMBERTO', 'year': 2019, 'dec': -30}, {'name': 'LORENZO', 'year': 2019, 'dec': -40}, {'name': 'GENEVIEVE', 'year': 2020, 'dec': -35}]

STRONGEST = [{'name': 'ALLEN', 'year': 1980, 'wind': 165},
			 {'name': 'LBRDAY', 'year': 1935, 'wind': 160},
			 {'name': 'GILBERT', 'year': 1988, 'wind': 160},
			 {'name': 'DORIAN', 'year': 2019, 'wind': 160},
			 {'name': 'WILMA', 'year': 2005, 'wind': 160},
			 {'name': 'MITCH', 'year': 1998, 'wind': 155},
			 {'name': 'RITA', 'year': 2005, 'wind': 155},
			 {'name': 'IRMA', 'year': 2017, 'wind': 155},
			 {'name': 'CUBA', 'year': 1932, 'wind': 150},
			 {'name': 'JANET', 'year': 1955, 'wind': 150},
			 {'name': 'CAMILLE', 'year': 1969, 'wind': 150},
			 {'name': 'ANITA', 'year': 1977, 'wind': 150},
			 {'name': 'DAVID', 'year': 1979, 'wind': 150},
			 {'name': 'ANDREW', 'year': 1992, 'wind': 150},
			 {'name': 'KATRINA', 'year': 2005, 'wind': 150},
			 {'name': 'DEAN', 'year': 2007, 'wind': 150},
			 {'name': 'FELIX', 'year': 2007, 'wind': 150},
			 {'name': 'MARIA', 'year': 2017, 'wind': 150}]

TOP10WETTEST = [{'rank': 1, 'total': 60.58, 'name': 'HARVEY', 'year': 2017, 'location': 'Nederland, TX'},
				{'rank': 2, 'total': 48.00, 'name': 'AMELIA', 'year': 1978, 'location': 'Medina, TX'},
				{'rank': 3, 'total': 45.20, 'name': 'EASY', 'year': 1950, 'location': 'Yankeetown, FL'},
				{'rank': 4, 'total': 45.00, 'name': 'CLAUDETTE', 'year': 1979, 'location': 'Alvin, TX'},
				{'rank': 5, 'total': 43.31, 'name': 'IMELDA', 'year': 2019, 'location': 'Jefferson County, TX'},
				{'rank': 6, 'total': 40.68, 'name': 'ALLISON', 'year': 2001, 'location': 'NW Jefferson County, TX'},
				{'rank': 7, 'total': 38.46, 'name': 'GEORGES', 'year': 1998, 'location': 'Munson, FL'},
				{'rank': 8, 'total': 36.71, 'name': 'DANNY', 'year': 1997, 'location': 'Dauphin Island Sea Lab, AL'},
				{'rank': 9, 'total': 35.93, 'name': 'FLORENCE', 'year': 2018, 'location': 'Elizabethtown, NC'},
				{'rank': 10, 'total': 29.76, 'name': 'UNNAMED-01', 'year': 1960, 'location': 'Port Lavaca #2, TX'}]

META = [{'year': 1950, 'name': 'EASY', '24h': ' ', 'total': 45.2, 'location': 'FL', 'notes': 'state record'},
		{'year': 1960, 'name': 'UNNAMED-01', '24h': 22, 'total': ' ', 'location': ' ', 'notes': 'KY state record (11.25)'},
		{'year': 1962, 'name': 'TD3', '24h': 22, 'total': ' ', 'location': 'LA', 'notes': 'state 24h record'},
		{'year': 1963, 'name': 'FLORA', '24h': 28.39, 'total': 100.39, 'location': 'Cuba', 'notes': '2nd highest in western hemisphere'},
		{'year': 1972, 'name': 'AGNES', '24h': '', 'total': ' ', 'location': '', 'notes': 'PA TC record (19.0)'},
		{'year': 1979, 'name': 'CLAUDETTE', '24h': 42, 'total': ' ', 'location': '', 'notes': 'US 24h record'},
		{'year': 1979, 'name': 'FREDERIC', '24h': '', 'total': ' ', 'location': '', 'notes': 'OH TC record (8.67)'},
		{'year': 1980, 'name': 'HERMINE', '24h': '', 'total': 31.15, 'location': 'Mexico', 'notes': ''},
		{'year': 1982, 'name': 'CHRIS', '24h': '', 'total': ' ', 'location': '', 'notes': 'TN TC record (13.6)'},
		{'year': 1994, 'name': 'ALBERTO', '24h': ' ', 'total': 27.85, 'location': 'GA', 'notes': 'state record'},
		{'year': 1997, 'name': 'DANNY', '24h': 32.52, 'total': 36.71, 'location': 'AL', 'notes': 'state record'},
		{'year': 1998, 'name': 'MITCH', '24h': ' ', 'total': 62.87, 'location': 'Honduras, Nicaragua', 'notes': '11,000 fatalities'},
		{'year': 1998, 'name': 'GEORGES', '24h': ' ', 'total': 38.46, 'location': 'FL/MS', 'notes': 'MS state record (32.21)'},
		{'year': 2000, 'name': 'KEITH', '24h': ' ', 'total': 32.67, 'location': 'Belize', 'notes': 'record'},
		{'year': 2001, 'name': 'ALLISON', '24h': ' ', 'total': '', 'location': '', 'notes': 'LA 2nd highest'},
		{'year': 2005, 'name': 'DENNIS', '24h': ' ', 'total': 42.99, 'location': 'Cuba', 'notes': '2nd highest'},
		{'year': 2005, 'name': 'WILMA', '24h': 64.33, 'total': ' ', 'location': '', 'notes': 'record 24h Western Hemisphere'},
		{'year': 2007, 'name': 'NOEL', '24h': ' ', 'total': 29.43, 'location': 'Bahamas', 'notes': 'record'},
		{'year': 2017, 'name': 'HARVEY', '24h': ' ', 'total': 60.58, 'location': 'TX', 'notes': 'TX and US record'},
		{'year': 2018, 'name': 'FLORENCE', '24h': ' ', 'total': 35.93, 'location': 'NC/SC', 'notes': 'state records'},
		{'year': 2019, 'name': 'BARRY', '24h': ' ', 'total': ' ', 'location': '', 'notes': 'AR state record (16.59)'},
		{'year': 2019, 'name': 'DORIAN', '24h': ' ', 'total': 22.84, 'location': 'Bahamas', 'notes': '2nd highest'}]

# NOTE: all labels below need to be unique text since they are used as keys
# 6 storm categories
STORMS6 = {'min': [35, 55, 70, 85, 105, 125],
		   'max': [54, 69, 84, 104, 124, 999],
		   # Near-land trends since 1920 for correcting counts and ACE
		   'trends': [-0.00230, 0.000785, -0.00209, -0.001615, -0.001824, -0.001067],
		   'colors': ['green', 'aqua', 'blue', 'purple', 'red', 'black'],
		   'labels': ['35-54', '55-69', '70-84', '85-104', '105-124', '>=125']}

# 4 storm categories
STORMS4 = {'min': [35, 69, 91, 120],
		   'max': [68, 90, 119, 999],
		   # Near-land trends since 1920 for correcting counts and ACE
		   'trends': [-0.001996, -0.00179, -0.000775, -0.001012],
		   'colors': ['green', 'blue', 'red', 'black'],
		   'labels': ['35-68', '69-90', '91-119', '>=120']}

RI24 = {'title': "Percent of all hurricanes with rapid 24h intensification  ",
		'min': [30, 40, 50, 60],
		'colors': ['blue', 'purple', 'red', 'black'],
		'labels': ['RI>=30', 'RI>=40', 'RI>=50', 'RI>=60']}

RD24 = {'title': "Percent of all hurricanes with rapid 24h decreases over water ",
		'min': [-10, -20, -30, -40],
		'colors': ['blue', 'purple', 'red', 'black'],
		'labels': ['D>=-10', 'D>=-20', 'D>=-30', 'D>=-40']}

STARTINGWINDS = {'min': [0, 35, 50, 65, 80, 105],
				 'max': [34, 49, 64, 79, 104, 999],
				 'colors': ['orange', 'lightgray', 'darkgray', 'gray', 'dimgray', 'black'],
				 'labels': ['<35', '35-49', '50-64', '65-79', '80-104', '>=105']}

SLOWING = {'title': "Percent of landfalling storms with slow motion ",
		   'max': [3, 6, 9, 12],
		   'colors': ['black', 'purple', 'blue', 'green'],
		   'labels': ['0-3', '0-6', '0-9', '0-12']}

elevations = Elevations();
elevations.loadFiles();

# HURDAT2 has two types of rows, first for each storm, second for each storm report
COLUMNS1 = {"desig": 0, "name": 1, "rows": 2}
COLUMNS2 = {"ymd": 0, "time": 1, "landfall": 2, "stormType": 3, "lat": 4, "lon": 5, "wind": 6, "pressure": 7}

# IBTRACS has only one row type:
COLUMN_NAMES_IB = ['SID','SEASON','NUMBER','BASIN','SUBBASIN','NAME','ISO_TIME','NATURE','LAT','LON','WMO_WIND','WMO_PRES','WMO_AGENCY','TRACK_TYPE','DIST2LAND','LANDFALL','IFLAG','USA_AGENCY','USA_ATCF_ID','USA_LAT','USA_LON','USA_RECORD','USA_STATUS','USA_WIND','USA_PRES','USA_SSHS','USA_R34_NE','USA_R34_SE','USA_R34_SW','USA_R34_NW','USA_R50_NE','USA_R50_SE','USA_R50_SW','USA_R50_NW','USA_R64_NE','USA_R64_SE','USA_R64_SW','USA_R64_NW','USA_POCI','USA_ROCI','USA_RMW','USA_EYE','TOKYO_LAT','TOKYO_LON','TOKYO_GRADE','TOKYO_WIND','TOKYO_PRES','TOKYO_R50_DIR','TOKYO_R50_LONG','TOKYO_R50_SHORT','TOKYO_R30_DIR','TOKYO_R30_LONG','TOKYO_R30_SHORT','TOKYO_LAND','CMA_LAT','CMA_LON','CMA_CAT','CMA_WIND','CMA_PRES','HKO_LAT','HKO_LON','HKO_CAT','HKO_WIND','HKO_PRES','NEWDELHI_LAT','NEWDELHI_LON','NEWDELHI_GRADE','NEWDELHI_WIND','NEWDELHI_PRES','NEWDELHI_CI','NEWDELHI_DP','NEWDELHI_POCI','REUNION_LAT','REUNION_LON','REUNION_TYPE','REUNION_WIND','REUNION_PRES','REUNION_TNUM','REUNION_CI','REUNION_RMW','REUNION_R34_NE','REUNION_R34_SE','REUNION_R34_SW','REUNION_R34_NW','REUNION_R50_NE','REUNION_R50_SE','REUNION_R50_SW','REUNION_R50_NW','REUNION_R64_NE','REUNION_R64_SE','REUNION_R64_SW','REUNION_R64_NW','BOM_LAT','BOM_LON','BOM_TYPE','BOM_WIND','BOM_PRES','BOM_TNUM','BOM_CI','BOM_RMW','BOM_R34_NE','BOM_R34_SE','BOM_R34_SW','BOM_R34_NW','BOM_R50_NE','BOM_R50_SE','BOM_R50_SW','BOM_R50_NW','BOM_R64_NE','BOM_R64_SE','BOM_R64_SW','BOM_R64_NW','BOM_ROCI','BOM_POCI','BOM_EYE','BOM_POS_METHOD','BOM_PRES_METHOD','NADI_LAT','NADI_LON','NADI_CAT','NADI_WIND','NADI_PRES','WELLINGTON_LAT','WELLINGTON_LON','WELLINGTON_WIND','WELLINGTON_PRES','DS824_LAT','DS824_LON','DS824_STAGE','DS824_WIND','DS824_PRES','TD9636_LAT','TD9636_LON','TD9636_STAGE','TD9636_WIND','TD9636_PRES','TD9635_LAT','TD9635_LON','TD9635_WIND','TD9635_PRES','TD9635_ROCI','NEUMANN_LAT','NEUMANN_LON','NEUMANN_CLASS','NEUMANN_WIND','NEUMANN_PRES','MLC_LAT','MLC_LON','MLC_CLASS','MLC_WIND','MLC_PRES','USA_GUST','BOM_GUST','BOM_GUST_PER','REUNION_GUST','REUNION_GUST_PER','USA_SEAHGT','USA_SEARAD_NE','USA_SEARAD_SE','USA_SEARAD_SW','USA_SEARAD_NW','STORM_SPEED','STORM_DIR']
col = 0
COLUMNS_IB = {}
for name in COLUMN_NAMES_IB:
	COLUMNS_IB[name] = col
	col = col + 1

# slow moving landfall table
class SpeedTable():
	def __init__(self, lower, upper):
		self.lowerThresh  = lower
		self.upperThresh = upper
		self.table = "<TABLE id=\"HURTABLE\"><THEAD><TR><TH>Year</TH><TH>Name</TH><TH>speed<br>mph</TH><TH>rank<br>US</TH><TH>Rain<br>24 hr</TH><TH>Rain<br>total</TH><TH>Notes</TH></TR></THEAD>"

	def addYear(self, year):
		stormCount = 0
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['slowestSpeedNearLand'] <= self.upperThresh:
				stormCount = stormCount + 1
		if stormCount == 0:
			return
		firstRow = True
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['slowestSpeedNearLand'] <= self.upperThresh:
				if firstRow:
					self.table = self.table + "<TBODY>\n\t<TR><TD rowspan=" + str(stormCount) + ">" + str(year.year) + "</TD>"
					firstRow = False
				else:
					self.table = self.table + "\t<TR>"
				if storm['slowestSpeedNearLand'] <= self.lowerThresh:
					self.table = self.table + "<TD class=\"highlight\">"
				else:
					self.table = self.table + "<TD>"
				#Year Name speed USrank 24hrRain totalRain Notes
				self.table = self.table + storm['name'] + "</TD><TD>" + str(storm['slowestSpeedNearLand']) + "</TD>"
				foundTop10 = False
				for top10 in TOP10WETTEST:
					if top10['year'] == year.year and top10['name'] == storm['name']:
						foundTop10 = True
						break
				if foundTop10:
					self.table = self.table + "<TD>" + str(top10['rank']) + "</TD>"
				else:
					self.table = self.table + "<TD></TD>"
				foundMeta = False
				for row in META:
					if row['year'] == year.year and row['name'] == storm['name']:
						foundMeta = True
						break
				if foundMeta:
					self.table = self.table + "<TD>" + str(row['24h']) + "</TD>"
					self.table = self.table + "<TD>" + str(row['total']) + "</TD>"
					self.table = self.table + "<TD>" + str(row['location']) + ' ' + str(row['notes']) + "</TD>"
				else:
					self.table = self.table + "<TD></TD><TD></TD><TD></TD>"
				self.table = self.table + "</TR>\n"
		self.table = self.table + "</TBODY>\n"

	def fini(self):
		self.table = self.table + "</TABLE>"
		return self.table

# RI Table
class RITable():
	def __init__(self, lower, upper):
		self.lowerThresh  = lower
		self.upperThresh = upper
		self.table = "<TABLE id=\"HURTABLE\"><THEAD><TR><TH>Year</TH><TH>Name</TH><TH>24h<br>inc</TH><TH>36h<br>inc</TH><TH>6h<br>inc</TH><TH>peak<br>wind</TH><TH>24h<br>decr</TH></TR></THEAD>"

	def addYear(self, year):
		stormCount = 0
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['max24Inc'] >= self.lowerThresh:
				stormCount = stormCount + 1
		if stormCount == 0:
			return
		firstRow = True
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['max24Inc'] >= self.lowerThresh:
				if firstRow:
					self.table = self.table + "<TBODY>\n\t<TR><TD rowspan=" + str(stormCount) + ">" + str(year.year) + "</TD>"
					firstRow = False
				else:
					self.table = self.table + "\t<TR>"
				if storm['max24Inc'] >= self.upperThresh:
					self.table = self.table + "<TD class=\"highlight\">"
				else:
					self.table = self.table + "<TD>"
				#Year Name ri24 ri36 ri6 peak
				self.table = self.table + storm['name'] + "</TD><TD>" + str(storm['max24Inc']) + "</TD>"
				self.table = self.table + "<TD>" + str(storm['max36Inc']) + "</TD>"
				self.table = self.table + "<TD>" + str(storm['max6Inc']) + "</TD>"
				foundStrongest = False
				for row in STRONGEST:
					if row['year'] == year.year and row['name'] == storm['name']:
						foundStrongest = True
						break
				if foundStrongest:
					self.table = self.table + "<TD>" + str(row['wind']) + "</TD>"
				else:
					self.table = self.table + "<TD></TD>"
				foundDecrease = False
				for row in DECREASES:
					if row['year'] == year.year and row['name'] == storm['name']:
						foundDecrease = True
						break
				if foundDecrease:
					self.table = self.table + "<TD>" + str(row['dec']) + "</TD>"
				else:
					self.table = self.table + "<TD></TD>"
				self.table = self.table + "</TR>\n"
		self.table = self.table + "</TBODY>\n"

	def fini(self):
		self.table = self.table + "</TABLE>"
		return self.table

class LFTable():
	def __init__(self):
		self.table = "<TABLE id=\"HURTABLE\"><THEAD><TR><TH>Year</TH><TH>Name</TH><TH>12h<br>inc</TH><TH>6h<br>inc</TH></TR></THEAD>"

	def addYear(self, year):
		stormCount = 0
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['maxInc6LF'] >= 10 or storm['maxInc12LF'] >= 15:
				stormCount = stormCount + 1
		if stormCount == 0:
			return
		firstRow = True
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['maxInc6LF'] >= 10 or storm['maxInc12LF'] >= 15:
				if firstRow:
					self.table = self.table + "<TBODY>\n\t<TR><TD rowspan=" + str(stormCount) + ">" + str(year.year) + "</TD>"
					firstRow = False
				else:
					self.table = self.table + "\t<TR>"
				self.table = self.table + "<TD>"
				#Year Name 12inc 6inc
				self.table = self.table + storm['name'] + "</TD>"
				self.table = self.table + "<TD>" + str(storm['maxInc12LF']) + "</TD>"
				self.table = self.table + "<TD>" + str(storm['maxInc6LF']) + "</TD>"
				self.table = self.table + "</TR>\n"
		self.table = self.table + "</TBODY>\n"

	def fini(self):
		self.table = self.table + "</TABLE>"
		return self.table

def RDList(years):
	rdlist = []
	for year in years:
		for stormNum in year.storms:
			storm = year.storms[stormNum]
			if storm['max24Dec'] <= -30:
				rdlist.append({'name': storm['name'], 'year': year.year, 'dec': storm['max24Dec']})
	print(rdlist)

class Year():
	def __init__(self, yearNum):
		self.year = yearNum
		self.storms = {}
		self.stormNum = 0

	def addStorm(self, storm):
		self.storms[self.stormNum] = storm.summary
		self.stormNum = self.stormNum + 1

# FROM STORMS:
#{'desig': 'AL141990', 'madeTS': True, 'madeHU': True, 'firstWind': 45, 'lastWind': 40, 'maxW': 65, 'ace': 5.7875, 'n24HU': 6, 'n24RI': 0, 'max6Inc': 5, 'max24Inc': 15, 'max36Inc': 15, 'max6Dec': -10, 'max24Dec': -15, 'windAtLandfall': 0, 'wind6AfterLandfall': 0, 'wind24AfterLandfall': 0, 'slowestSpeedNearLand': 999}
#{'desig': 'AL151990', 'madeTS': True, 'madeHU': False, 'firstWind': 25, 'lastWind': 15, 'maxW': 55, 'ace': 1.4475, 'n24HU': 0, 'n24RI': 0, 'max6Inc': 5, 'max24Inc': 20, 'max36Inc': 25, 'max6Dec': -10, 'max24Dec': -20, 'windAtLandfall': 25, 'wind6AfterLandfall': 0, 'wind24AfterLandfall': 0, 'slowestSpeedNearLand': 6.990032819711232}
#{'desig': 'AL161990', 'madeTS': True, 'madeHU': True, 'firstWind': 25, 'lastWind': 20, 'maxW': 75, 'ace': 6.1725, 'n24HU': 6, 'n24RI': 0, 'max6Inc': 10, 'max24Inc': 30, 'max36Inc': 40, 'max6Dec': -10, 'max24Dec': -35, 'windAtLandfall': 0, 'wind6AfterLandfall': 0, 'wind24AfterLandfall': 0, 'slowestSpeedNearLand': 999}
# TO YEAR:
#1990 {'numTS': 14, 'numHU': 8, 'total24HU': 76, 'total24RI': 0, 'ACE': 91.1675, '35-54': 3, '55-69': 4, '70-84': 4, '85-104': 2, '105-124': 1, '>=125': 0, '>=30': 4, '>=40': 0, '>=50': 0, '>=60': 0, '<35': 15, '35-49': 1, '50-64': 0, '65-79': 0, '80-104': 0, '>=105': 0, '0-3': 0, '0-6': 0, '0-9': 0, '0-12': 0}
	def summarize(self):
		self.summary = {'numTS': 0, 'numHU': 0, 'numLF': 0, 'total24HU': 0, 'total24RI': 0, 'ACE': 0}
		self.summary['avgWeakening'] = 999
		self.summary['extremeInc6LF'] = 0
		self.summary['avgInc6LF'] = 999
		self.summary['avgInc12LF'] = 999
		for label in STORMS4['labels']:
			self.summary[label] = 0
			self.summary['nl' + label] = 0
			self.summary['ace' + label] = 0
		for label in RI24['labels']:
			self.summary[label] = 0
		for label in RD24['labels']:
			self.summary[label] = 0
		for label in STARTINGWINDS['labels']:
			self.summary[label] = 0
		for label in SLOWING['labels']:
			self.summary[label] = 0
		totalWeakening = 0
		countOfWeakening = 0
		totalStrengthening6 = 0
		countOfStrengthening6 = 0
		totalStrengthening12 = 0
		countOfStrengthening12 = 0
		for stormNum in self.storms:
			storm = self.storms[stormNum]
			if storm['madeTS']:
				self.summary['numTS'] = self.summary['numTS'] + 1
			if storm['madeHU']:
				self.summary['numHU'] = self.summary['numHU'] + 1
			if storm['windAtLandfall'] > 0:
				self.summary['numLF'] = self.summary['numLF'] + 1
			self.summary['ACE'] = self.summary['ACE'] + storm['ace']
			self.summary['total24HU'] = self.summary['total24HU'] + storm['n24HU']
			self.summary['total24RI'] = self.summary['total24RI'] + storm['n24RI']
			if storm['landWeakening'] != 999:
				totalWeakening = totalWeakening + storm['landWeakening']
				countOfWeakening = countOfWeakening + 1
			if storm['madeLF'] and storm['madeHU']:
				#if storm['maxInc6LF'] > 0:
				#print(self.year, storm['name'], storm['maxInc6LF'])
				totalStrengthening6 = totalStrengthening6 + storm['maxInc6LF']
				countOfStrengthening6 = countOfStrengthening6 + 1
				#if storm['maxInc12LF'] > 0:
				#print(self.year, storm['name'], storm['maxInc12LF'])
				totalStrengthening12 = totalStrengthening12 + storm['maxInc12LF']
				countOfStrengthening12 = countOfStrengthening12 + 1
				if storm['maxInc6LF'] > self.summary['extremeInc6LF']:
					self.summary['extremeInc6LF'] = storm['maxInc6LF']
			for windMin, windMax, label in zip(STORMS4['min'], STORMS4['max'], STORMS4['labels']):
				if storm['maxW'] >= windMin and storm['maxW'] <= windMax:
					self.summary[label] = self.summary[label] + 1
					self.summary['ace' + label] = self.summary['ace' + label] + storm['ace']
					if storm['madeLF']:
						self.summary['nl' + label] = self.summary['nl' + label] + 1
			for riMin, label in zip(RI24['min'], RI24['labels']):
				if storm['max24Inc'] >= riMin:
					self.summary[label] = self.summary[label] + 1
			for rdMin, label in zip(RD24['min'], RD24['labels']):
				if storm['max24Dec'] <= rdMin:
					self.summary[label] = self.summary[label] + 1
			for swMin, swMax, label in zip(STARTINGWINDS['min'], STARTINGWINDS['max'], STARTINGWINDS['labels']):
				if storm['firstWind'] >= swMin and storm['firstWind'] <= swMax and storm['madeTS']:
					self.summary[label] = self.summary[label] + 1
			for slowMax, label in zip(SLOWING['max'], SLOWING['labels']):
				if storm['slowestSpeedNearLand'] <= slowMax:
					self.summary[label] = self.summary[label] + 1
		if countOfWeakening > 0:
			self.summary['avgWeakening'] = totalWeakening / countOfWeakening
		if countOfStrengthening6 > 0:
			self.summary['avgInc6LF'] = totalStrengthening6 / countOfStrengthening6
		if countOfStrengthening12 > 0:
			self.summary['avgInc12LF'] = totalStrengthening12 / countOfStrengthening12
		if PRINT:
			print(self.year, self.summary)

class Storm():
	def __init__HURDAT2(self, line):
		self.desig = line[COLUMNS1["desig"]]
		self.name = line[COLUMNS1["name"]].strip()
		if self.name == "UNNAMED":
			self.name = self.name + '-' + self.desig[2:4]
		self.nrows = int(line[COLUMNS1["rows"]])
		self.rows = {}
		self.rowNum = 0
		
	def __init__(self, line):
		self.desig = line[COLUMNS_IB["SID"]]
		self.name = line[COLUMNS_IB["NAME"]].strip()
		if self.name == "NOT_NAMED":
			self.name = self.desig
		self.rows = {}
		self.rowNum = 0
		self.addStormRow(line)
		
	# https://stackoverflow.com/questions/19412462/getting-distance-between-two-points-based-on-latitude-longitude
	def getDistance(self, lat1, lon1, lat2, lon2):
		# approximate radius of earth in miles
		R = 3960
		lat1 = radians(lat1)
		lon1 = radians(lon1)
		lat2 = radians(lat2)
		lon2 = radians(lon2)
		dlon = lon2 - lon1
		dlat = lat2 - lat1
		a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
		c = 2 * atan2(sqrt(a), sqrt(1 - a))
		distance = R * c
		return distance

	def convertLatitude(self, latString):
		if latString[-1] == 'N':
			return float(latString[0:-1])
		else:
			return float(latString[0:-1]) * -1.0
		
	def convertLongitude(self, lonString):
		if lonString[-1] == 'W':
			return float(lonString[0:-1]) * -1.0
		else:
			return float(lonString[0:-1])

	def addStormRow_HURDAT2(self, line):
		wind = int(line[COLUMNS2["wind"]])
		if wind == -99:
			return
		time = int(line[COLUMNS2["time"]])
		if time not in [0, 600, 1200, 1800]:
			return
		lat = self.convertLatitude(line[COLUMNS2["lat"]])
		lon = self.convertLongitude(line[COLUMNS2["lon"]])
		ele = elevations.getElevation(lon, lat)
		overland = False
		if ele != None and ele > -500:
			overland = True
		stormType = line[COLUMNS2["stormType"]].strip()
		self.rows[self.rowNum] = {'lat': lat, 'lon': lon, 'ele': ele, 'overland': overland, 'wind': wind, 'type': stormType}
		self.rowNum = self.rowNum + 1

	def addStormRow(self, line):
		windstr = line[COLUMNS_IB["USA_WIND"]]
		# ignore rows with negative or non-numeric wind
		if windstr.isdigit():
			wind = int(windstr)
		else:
			return
		datetime_str = line[COLUMNS_IB["ISO_TIME"]]
		# Format is YYYY-MM-DD HH:mm:ss
		datetime_obj = datetime.strptime(datetime_str, '%Y-%m-%d %H:%M:%S')
		if datetime_obj.time().hour not in [0, 6, 12, 18]:
			return
		lat = float(line[COLUMNS_IB["LAT"]])
		lon = float(line[COLUMNS_IB["LON"]])
		ele = elevations.getElevation(lon, lat)
		overland = False
		if ele != None and ele > -500:
			overland = True
		stormType = line[COLUMNS_IB["USA_STATUS"]].strip()
		self.rows[self.rowNum] = {'lat': lat, 'lon': lon, 'ele': ele, 'overland': overland, 'wind': wind, 'type': stormType}
		self.rowNum = self.rowNum + 1

#{'lat': 19.1, 'lon': -85.7, 'overland': False, 'wind': 45, 'type': 'TS'}
#{'lat': 19.7, 'lon': -85.5, 'overland': False, 'wind': 50, 'type': 'TS'}
#{'lat': 20.2, 'lon': -85.4, 'overland': False, 'wind': 60, 'type': 'TS'}
#{'lat': 20.9, 'lon': -85.1, 'overland': False, 'wind': 65, 'type': 'HU'}
#{'lat': 21.7, 'lon': -85.1, 'overland': False, 'wind': 75, 'type': 'HU'}
#{'lat': 22.7, 'lon': -85.2, 'overland': False, 'wind': 85, 'type': 'HU'}
#{'lat': 23.7, 'lon': -85.8, 'overland': False, 'wind': 85, 'type': 'HU'}
#{'lat': 24.6, 'lon': -86.2, 'overland': False, 'wind': 90, 'type': 'HU'}
#{'lat': 25.6, 'lon': -86.4, 'overland': False, 'wind': 100, 'type': 'HU'}
#{'lat': 26.6, 'lon': -86.5, 'overland': False, 'wind': 110, 'type': 'HU'}
#{'lat': 27.7, 'lon': -86.6, 'overland': False, 'wind': 120, 'type': 'HU'}
#{'lat': 29.0, 'lon': -86.3, 'overland': False, 'wind': 125, 'type': 'HU'}
#{'lat': 30.2, 'lon': -85.4, 'overland': True, 'wind': 135, 'type': 'HU'}
#{'lat': 31.5, 'lon': -84.5, 'overland': True, 'wind': 80, 'type': 'HU'}
#{'lat': 32.8, 'lon': -83.2, 'overland': True, 'wind': 50, 'type': 'TS'}
#{'lat': 34.1, 'lon': -81.7, 'overland': True, 'wind': 45, 'type': 'TS'}
#{'lat': 35.6, 'lon': -80.0, 'overland': True, 'wind': 45, 'type': 'TS'}
#{'lat': 36.5, 'lon': -77.7, 'overland': True, 'wind': 50, 'type': 'EX'}
	def summarizeStorm(self):
		if len(self.rows) == 0:
			return False

		self.summary = {'desig': self.desig, 'name': self.name,
						'madeTS': False, 'madeHU': False, 'madeLF': False,
						'firstWind': 0, 'lastWind': 0, 'maxW': 0, 'ace': 0,
						'n24HU': 0, 'n24RI': 0,
						'max6Inc': 0, 'max24Inc': 0, 'max36Inc': 0,
						'max6Dec': 0, 'max24Dec': 0, 'maxInc6LF': 0, 'maxInc12LF': 0,
						'windAtLandfall': 0, 'wind6AfterLandfall': 0, 'wind24AfterLandfall': 0,
						'landWeakening': 999, 'slowestSpeedNearLand': 999}

		# point to the last 6 rows 
		agos = [36, 30, 24, 18, 12, 6]
		rowsAgo = {}
		for ago in agos:
			rowsAgo[ago] = None

		for rownum in self.rows:
			row = self.rows[rownum]
			if PRINT:
				print(row)
			if self.summary['firstWind'] == 0:
				self.summary['firstWind'] = row['wind']
			if row['wind'] > self.summary['maxW']:
				self.summary['maxW'] = row['wind']
			if row['type'] == 'HU':
				self.summary['madeHU'] = True
			if row['type'] == 'TS':
				self.summary['madeTS'] = True
				if row['overland']:
					self.summary['madeLF'] = True

			# Official ACE: only use 6 hour intervals with TS or HU
			# validated with https://weather.fandom.com/wiki/1992_Atlantic_hurricane_season
			if row['type'] == 'HU' or row['type'] == 'TS':
				self.summary['ace'] = self.summary['ace'] + (row['wind'] * row['wind'])

			if row['type'] != 'EX':
				# Rapid Intensification, for any storm type
				#if row['type'] == 'HU' or row['type'] == 'TS':
				# Rapid Intensification, to hurricane only
				if row['type'] == 'HU':
					if rowsAgo[6] != None and row['wind'] - rowsAgo[6]['wind'] > self.summary['max6Inc']:
						self.summary['max6Inc'] = row['wind'] - rowsAgo[6]['wind']
					if rowsAgo[24] != None and row['wind'] - rowsAgo[24]['wind'] > self.summary['max24Inc']:
						self.summary['max24Inc'] = row['wind'] - rowsAgo[24]['wind']
					if rowsAgo[36] != None and row['wind'] - rowsAgo[36]['wind'] > self.summary['max36Inc']:
						self.summary['max36Inc'] = row['wind'] - rowsAgo[36]['wind']
					if self.summary['max36Inc'] < self.summary['max24Inc']:
						self.summary['max36Inc'] = self.summary['max24Inc']

				# find the highest 6 and 12 hour increases before landfall
				if rowsAgo[6] != None and not rowsAgo[6]['overland'] and row['overland'] and row['wind'] - rowsAgo[6]['wind'] > self.summary['maxInc6LF']:
					self.summary['maxInc6LF'] = row['wind'] - rowsAgo[6]['wind']
				if rowsAgo[12] != None and not rowsAgo[12]['overland'] and not rowsAgo[6]['overland'] and row['overland'] and row['wind'] - rowsAgo[12]['wind'] > self.summary['maxInc12LF']:
					self.summary['maxInc12LF'] = row['wind'] - rowsAgo[12]['wind']

				# 24h weakening over land, starting as HU
				if rowsAgo[18] != None and rowsAgo[18]['type'] == 'HU' and row['overland'] and rowsAgo[6]['overland'] and rowsAgo[12]['overland'] and rowsAgo[18]['overland']:
					if self.summary['landWeakening'] == 999:
						#print(self.desig, self.summary['name'], rowsAgo[18]['wind'], row['wind'])
						self.summary['landWeakening'] = row['wind'] - rowsAgo[18]['wind']

				# Rapid Weakening, excluding any over land, hurricane only
				if row['type'] == 'HU':
					if rowsAgo[6] != None and not row['overland'] and not rowsAgo[6]['overland'] and row['wind'] - rowsAgo[6]['wind'] < self.summary['max6Dec']:
						self.summary['max6Dec'] = row['wind'] - rowsAgo[6]['wind']
					if rowsAgo[24] != None and not row['overland'] and not rowsAgo[6]['overland'] and not rowsAgo[12]['overland'] and not rowsAgo[18]['overland'] and not rowsAgo[24]['overland'] and row['wind'] - rowsAgo[24]['wind'] < self.summary['max24Dec']:
						self.summary['max24Dec'] = row['wind'] - rowsAgo[24]['wind']

				if self.summary['windAtLandfall'] == 0 and row['overland']:
					self.summary['windAtLandfall'] = row['wind']

				# allow one TS reading before HU periods as a compromise for RI ratio
				if rowsAgo[24] != None and (rowsAgo[24]['type'] == 'HU' or rowsAgo[24]['type'] == 'TS') and rowsAgo[18]['type'] == 'HU' and rowsAgo[12]['type'] == 'HU' and rowsAgo[6]['type'] == 'HU' and row['type'] == 'HU':
				# no TS allowed.  Doesn't make much difference.
				#if rowsAgo[24] != None and (rowsAgo[24]['type'] == 'HU') and rowsAgo[18]['type'] == 'HU' and rowsAgo[12]['type'] == 'HU' and rowsAgo[6]['type'] == 'HU' and row['type'] == 'HU':
					self.summary['n24HU'] = self.summary['n24HU'] + 1
					# to match nature paper, "above 30 knots":
					#if row['wind'] - rowsAgo[24]['wind'] > 30:
					# to match "at least 30 knots in 24 hours"
					if row['wind'] - rowsAgo[24]['wind'] >= 30:
						self.summary['n24RI'] = self.summary['n24RI'] + 1

				# find the slowest 6 hour movement near landfall, but leave out TD only
				if self.summary['madeTS']:
					previousLat = 0
					previousLon = 0
					minDistance = 999
					nearLand = False
					for ago in agos:
						if rowsAgo[ago] != None:
							lat = rowsAgo[ago]['lat']
							lon = rowsAgo[ago]['lon']
							if rowsAgo[ago]['overland']:
								nearLand = True
							distance = self.getDistance(previousLat, previousLon, lat, lon)
							if distance < minDistance:
								minDistance = distance
							previousLat = lat
							previousLon = lon
					if nearLand and minDistance < 999:
						if self.summary['slowestSpeedNearLand'] > minDistance / 6:
							self.summary['slowestSpeedNearLand'] = round(minDistance / 6, 2)

			# shift the pointers to the last six rows and point to the current row
			for ago in agos:
				if ago > 6:
					rowsAgo[ago] = rowsAgo[ago - 6]
			rowsAgo[6] = row
		self.summary['ace'] = self.summary['ace'] / 10000
		self.summary['lastWind'] = row['wind']
		if PRINT:
			print(self.summary)
		return True

def read_data_HURDAT2(filename, startYear, endYear):
	years = []
	f = open(filename, 'r')
	csv_reader = csv.reader(f, delimiter=',')
	current_year = startYear
	year = Year(current_year)
	for line in csv_reader:
		firstToken = line[0]
		if firstToken.startswith(BASIN1) or firstToken.startswith(BASIN2):
			rows = int(line[COLUMNS1["rows"]])
			row = 0
			storm = Storm(line)
			yearNum = int(firstToken[4:9])
			# done with years we want
			if yearNum > endYear:
				break
			# skip over years we don't want
			if yearNum < current_year:
				continue
			# finished the current year
			if yearNum > current_year:
				year.summarize()
				years.append(year)
				current_year = yearNum
				year = Year(current_year)
		elif yearNum == current_year:
			storm.addStormRow(line)
			row = row + 1
			if row == rows:
				gotData = storm.summarizeStorm()
				# some storms are all wind=-99
				if gotData:
					year.addStorm(storm)
	year.summarize()
	years.append(year)
	return years
		
# ibtracs
def read_data(filename, startYear, endYear):
	years = []
	f = open(filename, 'r')
	csv_reader = csv.reader(f, delimiter=',')
	current_year = startYear
	current_storm = None
	year = Year(current_year)
	for line in csv_reader:
		# skip the two header lines
		if line[0] == 'SID' and line[1] == 'SEASON':
			continue
		if line[1] == 'Year':
			continue
		yearNum = int(line[COLUMNS_IB["SEASON"]])
		# skip over years until the starting year
		if yearNum < current_year:
			continue
		stormID = line[COLUMNS_IB["SID"]]
		if current_storm == None:
			current_storm = stormID
			storm = Storm(line)
		if stormID != current_storm:
			# done with storm
			gotData = storm.summarizeStorm()
			# some storms are all wind=-99
			if gotData:
				year.addStorm(storm)
			# done with years we want
			if yearNum > endYear:
				break
			# finished the current year
			if yearNum > current_year:
				year.summarize()
				years.append(year)
				current_year = yearNum
				year = Year(current_year)
			# start new storm
			current_storm = stormID
			storm = Storm(line)
		else:
			storm.addStormRow(line)
	year.summarize()
	years.append(year)
	return years
		
def plotSpeed(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	table = SpeedTable(3, 6)
	for year in years:
		table.addYear(year)
	html = table.fini()
	f = open("slowstorms.html", "w")
	f.write(html)
	f.close()

	fig = plt.figure(figsize=(9,3))

	for slowMax, color, label in zip(SLOWING['max'], SLOWING['colors'], SLOWING['labels']):
		validYears = []
		validPs = []
		for year in years:
			p = year.summary[label] / year.summary['numLF'] * 100
			validYears.append(year.year)
			validPs.append(p)

		axes = plt.gca()
		plt.scatter(validYears, validPs, color=color, label=label, alpha=0.6)

		if len(validYears) > 0:
			slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validPs)
			print(slowMax, slope)
			points = [slope * y + intercept for y in validYears]
			plt.plot(validYears, points, color=color, alpha=0.5)

	plt.legend(ncol = 4, loc='upper left')
	plt.title(SLOWING['title'] + str(yearStart) + "-" + str(yearEnd))
	pngFile = "slow" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotRI(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	table = RITable(30, 50)
	for year in years:
		table.addYear(year)
	html = table.fini()
	f = open("ristorms.html", "w")
	f.write(html)
	f.close()

	fig = plt.figure(figsize=(9,3))

	for min, color, label in zip(RI24['min'], RI24['colors'], RI24['labels']):
		validYears = []
		validPs = []
		for year in years:
			# use percent of TS 
			#p = year.summary[label] / year.summary['numTS'] * 100
			# use percent of HU
			p = year.summary[label] / year.summary['numHU'] * 100
			validYears.append(year.year)
			validPs.append(p)

		axes = plt.gca()
		plt.scatter(validYears, validPs, color=color, label=label, alpha=0.6)

		if len(validYears) > 0:
			slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validPs)
			print(min, slope)
			points = [slope * y + intercept for y in validYears]
			plt.plot(validYears, points, color=color, alpha=0.5)

	plt.legend(ncol = 4, loc='upper right')
	plt.title(RI24['title'] + str(yearStart) + "-" + str(yearEnd))
	pngFile = "ri" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotRIRatio(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	validYears = []
	validRatios = []
	for year in years:
		r = year.summary['total24RI'] / year.summary['total24HU']
		validYears.append(year.year)
		validRatios.append(r)

	plt.bar(validYears, validRatios, color='red', alpha=0.6)
	slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validRatios)
	points = [slope * y + intercept for y in validYears]
	print('slope', slope)
	plt.plot(validYears, points, color='red', alpha=0.5)

	plt.title('RI ratio for ' + str(yearStart) + "-" + str(yearEnd) + " using >= 30 kt (24 hour)")
	pngFile = "riratio" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotRD(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	RDList(years)

	fig = plt.figure(figsize=(9,3))

	for min, color, label in zip(RD24['min'], RD24['colors'], RD24['labels']):
		validYears = []
		validPs = []
		for year in years:
			p = year.summary[label] / year.summary['numTS'] * 100
			validYears.append(year.year)
			validPs.append(p)

		axes = plt.gca()
		plt.scatter(validYears, validPs, color=color, label=label, alpha=0.6)

		if len(validYears) > 0:
			slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validPs)
			print(min, slope)
			points = [slope * y + intercept for y in validYears]
			plt.plot(validYears, points, color=color, alpha=0.5)

	plt.legend(ncol = 4, loc='upper right')
	plt.title(RD24['title'] + str(yearStart) + "-" + str(yearEnd))
	pngFile = "rd" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotSW(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	for color, label in zip(STARTINGWINDS['colors'], STARTINGWINDS['labels']):
		validYears = []
		validPs = []
		for year in years:
			p = year.summary[label] / year.summary['numTS'] * 100
			validYears.append(year.year)
			validPs.append(p)

		axes = plt.gca()
		plt.bar(validYears, validPs, color=color, label=label, alpha=0.8)

	plt.legend(ncol = 3, loc='upper right')
	plt.title("starting winds " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "sw" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotNearLand(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	for color, label in zip(STORMS4['colors'], STORMS4['labels']):
		validYears = []
		validPercents = []
		for year in years:
			if year.summary[label] > 0:
				percent = year.summary['nl' + label] / year.summary[label] * 100
				validYears.append(year.year)
				validPercents.append(percent)

		axes = plt.gca()
		plt.scatter(validYears, validPercents, color=color, alpha=0.5)

		slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validPercents)
		points = [slope * y + intercept for y in validYears]
		print(label, slope)
		plt.plot(validYears, points, color=color, label=label, alpha=0.9)

	plt.legend(loc='upper right')
	plt.title("percent of storms near land " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "nl" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotCounts(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	for color, label, trend in zip(STORMS4['colors'], STORMS4['labels'], STORMS4['trends']):
		validYears = []
		validCounts = []
		for year in years:
			count = year.summary[label]
			# correct for detection/recording trend
			count = count * (1 - (trend * (y2 - year.year)))
			validYears.append(year.year)
			validCounts.append(count)

		axes = plt.gca()
		plt.bar(validYears, validCounts, color=color, label=label, alpha=0.8)

		slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validCounts)
		points = [slope * y + intercept for y in validYears]
		print(label, slope)
		plt.plot(validYears, points, color=color, alpha=0.9)

	plt.legend(ncol = 4, loc='upper left')
	plt.title("Adjusted storm counts " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "count" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotACE(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	color = "black"
	validYears = []
	validACE = []
	for year in years:
		aceTotal = 0
		for label, trend in zip(STORMS4['labels'], STORMS4['trends']):
			if label == '>=120':
				ace = year.summary['ace' + label]
				# correct for detection/recording trend
				aceTotal = aceTotal + ace * (1 - (trend * (y2 - year.year)))
		validYears.append(year.year)
		validACE.append(aceTotal)

	axes = plt.gca()
	plt.bar(validYears, validACE, color=color, label="ACE", alpha=0.5)

	slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validACE)
	points = [slope * y + intercept for y in validYears]
	print(label, slope)
	plt.plot(validYears, points, color=color, alpha=0.9)

	plt.legend(loc='upper center')
	plt.title("Adjusted ACE using only '>=120' " + str(yearStart) + "-" + str(yearEnd))
	#plt.title("Adjusted ACE " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "ace" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotWeakening(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	fig = plt.figure(figsize=(9,3))

	color = "black"
	validYears = []
	validAvgs = []
	for year in years:
		avg = year.summary['avgWeakening']
		if avg != 999:
			validYears.append(year.year)
			validAvgs.append(avg)

	axes = plt.gca()
	plt.scatter(validYears, validAvgs, color=color, alpha=0.5)

	slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validAvgs)
	points = [slope * y + intercept for y in validYears]
	print('slope', slope, points[0], points[-1])
	#plt.plot(validYears, points, color=color, alpha=0.9)

	plt.title("Average weakening in 24 hours after landfall " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "weakening" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

def plotLFStrengthening(y1, y2):
	yearStart = y1
	yearEnd = y2
	years = read_data(FILENAME, yearStart, yearEnd)

	table = LFTable()
	for year in years:
		table.addYear(year)
	html = table.fini()
	f = open("lfstorms.html", "w")
	f.write(html)
	f.close()

	fig = plt.figure(figsize=(9,3))

	color = "black"
	label = "6h"
	validYears = []
	validAvgs = []
	for year in years:
		avg = year.summary['avgInc6LF']
		if avg != 999:
			validYears.append(year.year)
			validAvgs.append(avg)

	axes = plt.gca()
	plt.scatter(validYears, validAvgs, color=color, label=label, alpha=0.5)

	slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validAvgs)
	points = [slope * y + intercept for y in validYears]
	print('slope', slope, points[0], points[-1])
	plt.plot(validYears, points, color=color, alpha=0.9)

	color = "red"
	label = "12h"
	validYears = []
	validAvgs = []
	for year in years:
		avg = year.summary['avgInc12LF']
		if avg != 999:
			validYears.append(year.year)
			validAvgs.append(avg)

	axes = plt.gca()
	plt.scatter(validYears, validAvgs, color=color, label=label, alpha=0.5)

	slope, intercept, r_value, p_value, std_err = stats.linregress(validYears, validAvgs)
	points = [slope * y + intercept for y in validYears]
	print('slope', slope, points[0], points[-1])
	plt.plot(validYears, points, color=color, alpha=0.9)

	plt.legend(ncol=2, loc='upper right')
	plt.title("Average strengthening before landfall " + str(yearStart) + "-" + str(yearEnd))
	pngFile = "strenthening" + str(yearStart) + ".png"
	plt.savefig(pngFile)
	plt.show()

if __name__ == '__main__':	
	#plotSpeed(1950, 2020)
	#plotSpeed(1990, 2020)
	#plotRI(1950, 2020)
	#plotRI(1990, 2020)
	#plotRIRatio(1982, 2009)
	#plotRD(1950, 2020)
	#plotSW(1851, 2020)
	#plotNearLand(1851, 2020)
	#plotNearLand(1920, 2020)
	#plotCounts(1920, 2020)
	#plotACE(1920, 2020)
	#plotWeakening(1920, 2020)
	#plotLFStrengthening(1950, 2020)
