def updtChart(site_triplet, siteName): print('Working on WTEQ POR Chart for ' + siteName) statsData = [] minData = [] maxData = [] meanData = [] lowestData = [] highestData = [] lowData = [] highData = [] sliderDates = [] meanData = [] trace = [] sitePlotData = [] PORplotData = [] sitePlotNormData = [] validTrip = [site_triplet] sensor = r"WTEQ" date_series = [ date(2015, 10, 1) + datetime.timedelta(days=x) for x in range(0, 366) ] #could use any year with a leap day if validTrip: normData = [] for triplet in validTrip: url = '/'.join([ dataUrl, 'normals', 'DAILY', sensor, triplet.replace(':', '_') + '.json' ]) with request.urlopen(url) as d: jTemp = json.loads(d.read().decode()) normData.append(jTemp) sitePlotNormData = np.array(normData[0]['values'], dtype=np.float) sitePlotNormData = sitePlotNormData.tolist() beginDateDict = {} for siteMeta in meta: beginDateDict.update({ str(siteMeta['stationTriplet']): dt.strptime(str(siteMeta['beginDate']), "%Y-%m-%d %H:%M:%S") }) siteBeginDate = min(beginDateDict.values()) sYear = siteBeginDate.year if siteBeginDate.year > sYear: if siteBeginDate.month < 10: sYear = siteBeginDate.year else: if siteBeginDate.month == 10 and siteBeginDate.day == 1: sYear = siteBeginDate.year else: sYear = siteBeginDate.year + 1 sDate = date(sYear, 10, 1).strftime("%Y-%m-%d") eDate = today.date().strftime("%Y-%m-%d") data = [] for triplet in validTrip: url = '/'.join( [dataUrl, 'DAILY', sensor, triplet.replace(':', '_') + '.json']) with request.urlopen(url) as d: jTemp = json.loads(d.read().decode()) data.append(trimToOct1(jTemp)) for dataSite in data: if dataSite: padMissingData(dataSite, sDate, eDate) sitePlotData = np.array(data[0]['values'], dtype=np.float) PORplotData = list( [sitePlotData[i:i + 366] for i in range(0, len(sitePlotData), 366)]) allButCurrWY = list(PORplotData) del allButCurrWY[-1] statsData = list(map(list, zip(*allButCurrWY))) if len(statsData[0]) > 1: statsData[151] = statsData[150] with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RuntimeWarning) minData = [np.nanmin(a) for a in statsData] maxData = [np.nanmax(a) for a in statsData] meanData = [np.nanpercentile(a, 50) for a in statsData] lowestData = [np.nanpercentile(a, 10) for a in statsData] highestData = [np.nanpercentile(a, 90) for a in statsData] lowData = [np.nanpercentile(a, 30) for a in statsData] highData = [np.nanpercentile(a, 70) for a in statsData] future_date_pad = 14 if len(PORplotData[-1]) > 351: future_date_pad = 366 - len(PORplotData[-1]) - 1 sliderDates = list( chain([(date_series[0])] + [ date_series[get_last_non_zero_index(maxData[0:305]) + future_date_pad] ])) else: sliderDates = list(chain([(date_series[0])] + [date_series[-1]])) if len(PORplotData) > 0: for index, i in enumerate(PORplotData): if index == len(PORplotData) - 1: trace.extend([ go.Scatter(x=date_series, y=i, name=str(sYear + index + 1), visible=True, connectgaps=True, line=dict(color='rgb(0,0,0)')) ]) elif np.nansum(i) > 0: trace.extend([ go.Scatter(x=date_series, y=i, name=str(sYear + index + 1), visible='legendonly', connectgaps=True) ]) if meanData: if lowestData: trace.extend([ go.Scatter(x=date_series, y=minData, legendgroup='centiles', name=r'Min', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,0,1,0.15)', fill='none', showlegend=False, hoverinfo='none') ]) trace.extend([ go.Scatter(x=date_series, y=lowestData, legendgroup='centiles', name=r'10%', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,0,1,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if lowData: trace.extend([ go.Scatter(x=date_series, y=lowData, legendgroup='centiles', name=r'30%', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,237,0,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if highData: trace.extend([ go.Scatter(x=date_series, y=highData, legendgroup='centiles', name=r'Stats. Shading', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(115,237,115,0.15)', fill='tonexty', showlegend=True, hoverinfo='none') ]) if highestData: trace.extend([ go.Scatter(x=date_series, y=highestData, legendgroup='centiles', connectgaps=True, name=r'90%', visible=True, mode='line', line=dict(width=0), fillcolor='rgba(0,237,237,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) trace.extend([ go.Scatter(x=date_series, y=maxData, legendgroup='centiles', name=r'Max', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(1,0,237,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if minData: trace.extend([ go.Scatter(x=date_series, y=minData, name=r'Min', visible=True, hoverinfo='none', connectgaps=True, line=dict(color='rgba(237,0,0,0.5)')) ]) if len(sitePlotNormData) > 0: trace.extend([ go.Scatter(x=date_series, y=sitePlotNormData, name=r"Normal ('81-'10)", connectgaps=True, visible=True, hoverinfo='none', line=dict(color='rgba(0,237,0,0.4)')) ]) if meanData: if len(sitePlotNormData) > 0: trace.extend([ go.Scatter(x=date_series, y=meanData, name=r'Normal (POR)', visible='legendonly', hoverinfo='none', connectgaps=True, line=dict(color='rgba(0,237,0,0.4)', dash='dash')) ]) else: trace.extend([ go.Scatter(x=date_series, y=meanData, name=r'Normal (POR)', connectgaps=True, visible=True, hoverinfo='none', line=dict(color='rgba(0,237,0,0.4)')) ]) if maxData: trace.extend([ go.Scatter(x=date_series, y=maxData, name=r'Max', visible=True, hoverinfo='none', connectgaps=True, line=dict(color='rgba(0,0,237,0.4)')) ]) annoText = str( r"Statistical shading breaks at 10th, 30th, 50th, 70th, and 90th Percentiles<br>Normal ('81-'10) - Official median calculated from 1981 thru 2010 data <br>Normal (POR) - Unofficial mean calculated from Period of Record data <br>For more information visit: <a href='https://www.wcc.nrcs.usda.gov/normals/30year_normals_data.htm'>30 year normals calcuation description</a>" ) asterisk = '' if len(sitePlotNormData) == 0: sitePlotNormData = meanData annoText = annoText + '<br>*POR data used to calculate Normals since no published 30-year normals available for this site' asterisk = '*' jDay = len(PORplotData[-1]) - 1 if len(sitePlotNormData) == 0: perNorm = r'N/A' else: perNorm = str('{0:g}'.format( 100 * round(PORplotData[-1][jDay] / sitePlotNormData[jDay], 2))) perPeak = str('{0:g}'.format( 100 * round(PORplotData[-1][jDay] / max(sitePlotNormData), 2))) if not math.isnan(PORplotData[-1][jDay]): centile = ordinal( int( round( stats.percentileofscore(statsData[jDay], PORplotData[-1][jDay]), 0))) else: centile = 'N/A' dayOfPeak = sitePlotNormData.index(max(sitePlotNormData)) if jDay > dayOfPeak: tense = r'Since' else: tense = r'Until' daysToPeak = str(abs(jDay - dayOfPeak)) annoData = str(r"Current" + asterisk + ":<br>% of Normal - " + perNorm + r"%<br>" + r"% Normal Peak - " + perPeak + r"%<br>" + r"Days " + tense + r" Normal Peak - " + daysToPeak + r"<br>" r"Percentile Rank- " + centile) layout = go.Layout(images=[ dict( source= "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/US-NaturalResourcesConservationService-Logo.svg/2000px-US-NaturalResourcesConservationService-Logo.svg.png", xref="paper", yref="paper", x=0, y=0.9, xanchor="left", yanchor="bottom", sizex=0.4, sizey=0.1, opacity=0.5, layer="above") ], annotations=[ dict(font=dict(size=10), text=annoText, x=0, y=-0.41, yref='paper', xref='paper', align='left', showarrow=False), dict(font=dict(size=10), text=annoData, x=0, y=0.9, yref='paper', xref='paper', align='left', xanchor="left", yanchor="top", showarrow=False) ], legend=dict(traceorder='reversed', tracegroupgap=1, bordercolor='#E2E2E2', borderwidth=2), showlegend=True, title='Snow Water Equivalent at<br>' + siteName, height=622, width=700, autosize=False, yaxis=dict(title=r'Snow Water Equivalent (in.)', hoverformat='.1f', tickformat="0f"), xaxis=dict(range=sliderDates, tickformat="%b %e", rangeselector=dict(buttons=list([ dict(count=9, label='Jan', step='month', stepmode='todate'), dict(count=6, label='Apr', step='month', stepmode='todate'), dict(count=3, label='July', step='month', stepmode='todate'), dict(label='WY', step='all') ])), rangeslider=dict(thickness=0.1), type='date')) return {'data': trace, 'layout': layout}
def updtChart(basinName, basinSites): basin = basinName print('Working on PREC Projection Chart for ' + basinName) statsData = [] minData = [] maxData = [] meanData = [] lowestData = [] highestData = [] lowData = [] highData = [] sliderDates = [] meanData = [] trace = [] plotData = [] basinPlotData = [] PORplotData = [] basinNormData = [] basinPlotNormData = [] validTrip = [] networks = [r'SNTL', r'SCAN', r'SNTLT'] sensor = r"PREC" dataPath = path.join(this_dir, 'data', 'metaData', sensor, 'metaData.json') with open(dataPath, 'r') as j: meta = json.load(j) meta[:] = [ x for x in meta if str.split(x['stationTriplet'], ":")[2] in networks and str.split(x['stationTriplet'], ":")[0] in basinSites ] validTrip = [x['stationTriplet'] for x in meta] date_series = [ date(2015, 10, 1) + datetime.timedelta(days=x) for x in range(0, 366) ] #could use any year with a leap day if validTrip: normData = [] for triplet in validTrip: dataPath = dataPath = path.join( this_dir, 'data', 'norms', sensor, triplet.replace(':', '_') + '.json') with open(dataPath, 'r') as j: jTemp = json.load(j) normData.append(jTemp) basinNormData = [ np.array(x['values'], dtype=np.float) for x in normData if x['values'] ] if basinNormData: basinPlotNormData = list( np.nanmean(np.array([i for i in basinNormData]), axis=0)) validTrip[:] = [ x for index, x in enumerate(validTrip) if normData[index]['values'] ] beginDateDict = {} for siteMeta in meta: beginDateDict.update({ str(siteMeta['stationTriplet']): dt.strptime(str(siteMeta['beginDate']), "%Y-%m-%d %H:%M:%S") }) basinBeginDate = min(beginDateDict.values()) sYear = basinBeginDate.year if basinBeginDate.year > sYear: if basinBeginDate.month < 10: sYear = basinBeginDate.year else: if basinBeginDate.month == 10 and basinBeginDate.day == 1: sYear = basinBeginDate.year else: sYear = basinBeginDate.year + 1 sDate = date(sYear, 10, 1).strftime("%Y-%m-%d") eDate = (today.date() - datetime.timedelta(days=1)).strftime("%Y-%m-%d") data = [] for triplet in validTrip: dataPath = path.join(this_dir, 'data', sensor, triplet.replace(':', '_') + '.json') with open(dataPath, 'r') as j: jTemp = json.load(j) data.append(jTemp) for dataSite in data: if dataSite: padMissingData(dataSite, sDate, eDate) plotData = [np.array(x['values'], dtype=np.float) for x in data] with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RuntimeWarning) basinPlotData = list( np.nanmean(np.array([i for i in plotData]), axis=0)) PORplotData = list( [basinPlotData[i:i + 366] for i in range(0, len(basinPlotData), 366)]) allButCurrWY = list(PORplotData) del allButCurrWY[-1] statsData = list(map(list, zip(*allButCurrWY))) if len(statsData[0]) > 1: statsData[151] = statsData[150] with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RuntimeWarning) minData = [np.nanmin(a) for a in statsData] maxData = [np.nanmax(a) for a in statsData] meanData = [np.nanmean(a) for a in statsData] lowestData = [np.nanpercentile(a, 10) for a in statsData] highestData = [np.nanpercentile(a, 90) for a in statsData] lowData = [np.nanpercentile(a, 30) for a in statsData] highData = [np.nanpercentile(a, 70) for a in statsData] sliderDates = list(chain([(date_series[0])] + [date_series[-1]])) else: sliderDates = list(chain([(date_series[0])] + [date_series[-1]])) jDay = len(PORplotData[-1]) - 1 lastValue = PORplotData[-1][-1] nanList = [np.nan] * jDay projData = [ createPRECProjTrace(a, jDay, lastValue, nanList) for a in allButCurrWY ] statsProj = list(map(list, zip(*projData))) cleanStatsProj = list(statsProj) if cleanStatsProj: with warnings.catch_warnings(): warnings.simplefilter("ignore", category=RuntimeWarning) minProj = [np.nanmin(a) for a in cleanStatsProj] maxProj = [np.nanmax(a) for a in cleanStatsProj] medianProj = [np.nanpercentile(a, 50) for a in cleanStatsProj] lowestProj = [np.nanpercentile(a, 10) for a in cleanStatsProj] highestProj = [np.nanpercentile(a, 90) for a in cleanStatsProj] lowProj = [np.nanpercentile(a, 30) for a in cleanStatsProj] highProj = [np.nanpercentile(a, 70) for a in cleanStatsProj] if len(PORplotData) > 0: for index, i in enumerate(PORplotData): if index == len(PORplotData) - 1: trace.extend([ go.Scatter(x=date_series, y=i, name=str(sYear + index + 1), visible=True, connectgaps=True, line=dict(color='rgb(0,0,0)')) ]) elif np.nansum(i) > 0: trace.extend([ go.Scatter(x=date_series, y=projData[index], name=str(sYear + index + 1), visible='legendonly', connectgaps=True) ]) if medianProj: if minProj: trace.extend([ go.Scatter(x=date_series, y=minProj, name=r'Min Proj', visible=True, connectgaps=True, line=dict(color='rgba(237,0,0,0.4)')) ]) if lowestProj: trace.extend([ go.Scatter(x=date_series, y=lowestProj, name=r'10% Proj', visible=True, connectgaps=True, line=dict(color='rgba(237,0,1,0.4)')) ]) if lowProj: trace.extend([ go.Scatter(x=date_series, y=lowProj, name=r'30% Proj', visible=True, connectgaps=True, line=dict(color='rgba(0,237,0,0.4)')) ]) if medianProj: trace.extend([ go.Scatter(x=date_series, y=medianProj, name=r'50% Proj', connectgaps=True, visible=True, line=dict(color='rgba(0,237,0,0.4)')) ]) if highProj: trace.extend([ go.Scatter(x=date_series, y=highProj, name=r'70% Proj', visible=True, connectgaps=True, line=dict(color='rgba(115,237,115,0.4)')) ]) if highestProj: trace.extend([ go.Scatter(x=date_series, y=highestProj, connectgaps=True, name=r'90% Proj', visible=True, line=dict(color='rgba(1,237,237,0.4)')) ]) if maxProj: trace.extend([ go.Scatter(x=date_series, y=maxProj, name=r'Max Proj', visible=True, connectgaps=True, line=dict(color='rgba(0,0,237,0.4)')) ]) if meanData: if lowestData: trace.extend([ go.Scatter(x=date_series, y=minData, legendgroup='centiles', name=r'Min', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,0,1,0.15)', fill='none', showlegend=False, hoverinfo='none') ]) trace.extend([ go.Scatter(x=date_series, y=lowestData, legendgroup='centiles', name=r'10%', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,0,1,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if lowData: trace.extend([ go.Scatter(x=date_series, y=lowData, legendgroup='centiles', name=r'30%', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(237,237,0,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if highData: trace.extend([ go.Scatter(x=date_series, y=highData, legendgroup='centiles', name=r'Stats. Shading', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(115,237,115,0.15)', fill='tonexty', showlegend=True, hoverinfo='none') ]) if highestData: trace.extend([ go.Scatter(x=date_series, y=highestData, legendgroup='centiles', connectgaps=True, name=r'90%', visible=True, mode='line', line=dict(width=0), fillcolor='rgba(0,237,237,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) trace.extend([ go.Scatter(x=date_series, y=maxData, legendgroup='centiles', name=r'Max', visible=True, mode='line', line=dict(width=0), connectgaps=True, fillcolor='rgba(1,0,237,0.15)', fill='tonexty', showlegend=False, hoverinfo='none') ]) if basinPlotNormData: trace.extend([ go.Scatter(x=date_series, y=basinPlotNormData, name=r"Normal ('81-'10)", connectgaps=True, visible=True, hoverinfo='none', line=dict(color='rgba(0,237,0,0.4)')) ]) if meanData: if basinPlotNormData: trace.extend([ go.Scatter(x=date_series, y=meanData, name=r'Normal (POR)', visible='legendonly', hoverinfo='none', connectgaps=True, line=dict(color='rgba(0,237,0,0.4)', dash='dash')) ]) else: trace.extend([ go.Scatter(x=date_series, y=meanData, name=r'Normal (POR)', connectgaps=True, visible=True, hoverinfo='none', line=dict(color='rgba(0,237,0,0.4)')) ]) annoText = str( r"Statistical shading breaks at 10th, 30th, 50th, 70th, and 90th Percentiles<br>Normal ('81-'10) - Official mean calculated from 1981 thru 2010 data <br>Normal (POR) - Unofficial mean calculated from Period of Record data <br>For more information visit: <a href='https://www.wcc.nrcs.usda.gov/normals/30year_normals_data.htm'>30 year normals calcuation description</a>" ) asterisk = '' if not basinPlotNormData: basinPlotNormData = meanData annoText = annoText + '<br>*POR data used to calculate Normals since no published 30-year normals available for this basin' asterisk = '*' if basinPlotNormData[jDay] == 0: perNorm = r'N/A' else: perNorm = str('{0:g}'.format( 100 * round(PORplotData[-1][jDay] / basinPlotNormData[jDay], 2))) perPeak = str('{0:g}'.format( 100 * round(PORplotData[-1][jDay] / max(basinPlotNormData), 2))) if not math.isnan(PORplotData[-1][jDay]): centile = ordinal( int( round( stats.percentileofscore(statsData[jDay], PORplotData[-1][jDay]), 0))) else: centile = 'N/A' dayOfPeak = basinPlotNormData.index(max(basinPlotNormData)) if jDay > dayOfPeak: tense = r'Since' else: tense = r'Until' daysToPeak = str(abs(jDay - dayOfPeak)) annoData = str(r"Current" + asterisk + ":<br>% of Normal - " + perNorm + r"%<br>" + r"% of Yearly Avg - " + perPeak + r"%<br>" + r"Days " + tense + r" End of WY - " + daysToPeak + r"<br>" r"Percentile Rank- " + centile) layout = go.Layout(images=[ dict( source= "https://upload.wikimedia.org/wikipedia/commons/thumb/7/7f/US-NaturalResourcesConservationService-Logo.svg/2000px-US-NaturalResourcesConservationService-Logo.svg.png", xref="paper", yref="paper", x=0, y=0.9, xanchor="left", yanchor="bottom", sizex=0.4, sizey=0.1, opacity=0.5, layer="above") ], annotations=[ dict(font=dict(size=10), text=annoText, x=0, y=-0.41, yref='paper', xref='paper', align='left', showarrow=False), dict(font=dict(size=10), text=annoData, x=0, y=0.9, yref='paper', xref='paper', align='left', xanchor="left", yanchor="top", showarrow=False) ], legend=dict(traceorder='reversed', tracegroupgap=1, bordercolor='#E2E2E2', borderwidth=2), showlegend=True, title='Precipitation Projections in<br> ' + str(basin), height=622, width=700, autosize=False, yaxis=dict(title=r'Precipitation (in.)', hoverformat=".1f", tickformat="0f"), xaxis=dict(range=sliderDates, tickformat="%b %e", rangeselector=dict(buttons=list([ dict(count=9, label='Jan', step='month', stepmode='todate'), dict(count=6, label='Apr', step='month', stepmode='todate'), dict(count=3, label='July', step='month', stepmode='todate'), dict(label='WY', step='all') ])), rangeslider=dict(thickness=0.1), type='date')) return {'data': trace, 'layout': layout}