Customized plots for probabilistic forecast. In particular, this functions were used for wind forecast.
def plot_quantile_forecast(DF,shead,is_save=False,path_output=None):
"""
DF: columns --> [ dt, real, q5, q10, ..., q95 ]
"""
import numpy as np
import pandas as pd
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
# create objects
fig, ax = plt.subplots(figsize=(12,6))
# calculate if any number is the multiple of another number
def multiple(value, multiple):
rest = value % multiple
if rest == 0:
return True
else:
return False
# collect data
mask = np.array([multiple(i.hour, 6) for i in DF.dt.tolist()])
lsx = [ idt.strftime("%Y-%m-%d %Hh") if imask else '' for imask,idt in zip(mask,DF.dt.tolist())]
ix = list(range(0,len(lsx),1))
yreal = DF.real.tolist()
YPRED = DF[[ic for ic in DF.columns.values if 'q' in ic]]
# get list of range
lranges = ["q5-q95","q10-q90","q15-q85","q20-q80","q25-q75","q30-q70","q35-q65","q40-q60","q45-q55"]
# set color list (blues)
lblues = np.linspace(0.1,1.0,len(lranges))
# loop of ranges
for ir,ib in list(zip(lranges,lblues))[:]:
# get name of range limits
ipi,ipf = ir.split("-")
# get required percentiles in each range
ypqi = np.array([float(iv) for iv in YPRED[ipi].values])
ypqf = np.array([float(iv) for iv in YPRED[ipf].values])
# plot range of precentiles
#ax.plot(x_final,ypi,color="grey",linestyle="dashed")
#ax.plot(x_final,ypf,color="grey",linestyle="dashed")
# fill ranges
ax.fill_between(ix,ypqi,ypqf,color=(ib,ib,1.))
# collect extreme percentiles forecast
ypq5 = np.array([float(iv) for iv in YPRED['q5'].values])
ypq95 = np.array([float(iv) for iv in YPRED['q95'].values])
# plot extreme percentiles forecast
ax.plot(ix,ypq5,color="blue")
ax.plot(ix,ypq95,color="blue",label="Prob. Frcst")
# plot real
ax.plot(ix,yreal,color="black",linestyle="dashed" ,label="real")
plt.scatter(ix,yreal,s=20,facecolor="none",edgecolors="black")
# collect p50 forecast
ypq50 = np.array([float(iv) for iv in YPRED['q50'].values])
# plot p50 forecast
ax.plot(ix,ypq50,color="red",label="q50 Frcst")
# x limits
ax.set_xlim([ix[0]-1,ix[-1]+1])
# y limits
ax.set_ylim([0,1])
# xtick
plt.xticks(ix,fontsize='small',rotation='vertical')
ax.set_xticklabels(lsx)
# hide xticks
#plt.tick_params(axis='x',which='both',bottom='off',top='off',labelbottom='off')
# axes labels
plt.ylabel("wp normalized")
# lengend
ax.legend(loc='upper right',fancybox=True, shadow=True, ncol=1,fontsize=10)
# title
plt.title("%s: %s hour ahead"%(shead,((DF.dt.tolist()[-1]-DF.dt.tolist()[0]).days)*24))
# adjust space of chart
plt.subplots_adjust(bottom=0.2)
# display
if is_save is False: plt.show()
# save
else:
if path_output is None: print('WARNING: it was not specified the output path')
else: plt.savefig(path_output,bbox_inches='tight',transparent=False)
# close plot
plt.close(fig)
# return
return None
## PLOT QUANTILE FORECAST USING BOXPLOTS
def plot_quantile_forecast2(DF,shead):
import numpy as np
import matplotlib.pyplot as plt
from repository_scores import calculate_pinball_score,rmse,match_index
from repository_functions import multiple
fig, ax = plt.subplots(figsize=(30,10))
## data
lcolq = [ic for ic in DF.columns.values if 'q' in ic]
data = DF[lcolq].as_matrix()
data = np.transpose(data)
ldt = DF.datetime.tolist()
x = list(range(len(ldt)))
y = DF.real.tolist()
predictions = DF['q50'].values
# dates
lmut = np.array([multiple(idt.hour, 6) for idt in ldt])
lsdates = [idt.strftime("%Y-%m-%d %H") if imut else '' for imut,idt in zip(lmut,ldt)]
# match
lmatch = list(DF[['real','q5','q95']].apply(lambda x: True if x[0]>=float('%.1f'%x[1]) and x[0]<=float('%.1f'%x[2]) else False, axis=1))
# scores
pinball_score = np.mean(calculate_pinball_score(DF)['pinball'])
rmse_score = rmse(predictions, y)
vmatch_index = match_index(DF)
# Plot box plot per each line point
boxplot_dict = ax.boxplot(data, positions=x, notch=False)
# Plot a line between the means of each dataset
plt.plot(x, y,linewidth=5,color="black",linestyle="dashed" ,label='real')
# format general labels in x axis
plt.xticks(x,fontsize=20,rotation='vertical')
ax.set_xticklabels(lsdates)
plt.yticks(fontsize=20,rotation='horizontal')
# set limits
#ax.set_ylim([0,1])
# set legend
ax.legend(loc='best',fontsize=22,shadow=True)
# set color of box plots
i=0
for b in boxplot_dict['boxes']:
if lmatch[i]: b.set_color('green')
else:b.set_color('red')
i += 1
# title
if shead!='': shead = '%s:'%shead
plt.title('%s Pinball = %.3f Match Index = %.3f%s RMSE = %.3f \n [ %s - %s ]'%(shead,
pinball_score,
vmatch_index,'%',
rmse_score,
ldt[0],ldt[-1]),
fontsize=20)
# Plot
plt.show()
# return
return None