def change_variable_attributes(cfg, ds): """ Purpose: Clean up the variable attributes. Usage: Author: PRI Date: November 2018 """ # rename existing long_name to description, introduce a # consistent long_name attribute and introduce the group_name # attribute vattr_list = list(cfg["variable_attributes"].keys()) series_list = list(ds.series.keys()) descr = "description_" + ds.globalattributes["nc_level"] for label in series_list: variable = pfp_utils.GetVariable(ds, label) variable["Attr"][descr] = copy.deepcopy(variable["Attr"]["long_name"]) for item in vattr_list: if label[:len(item)] == item: for key in list(cfg["variable_attributes"][item].keys()): variable["Attr"][key] = cfg["variable_attributes"][item][ key] pfp_utils.CreateVariable(ds, variable) # parse variable attributes to new format, remove deprecated variable attributes # and fix valid_range == "-1e+35,1e+35" tmp = cfg["variable_attributes"]["deprecated"] deprecated = pfp_cfg.cfg_string_to_list(tmp) series_list = list(ds.series.keys()) for label in series_list: variable = pfp_utils.GetVariable(ds, label) # parse variable attributes to new format variable["Attr"] = parse_variable_attributes(variable["Attr"]) # remove deprecated variable attributes for vattr in deprecated: if vattr in list(variable["Attr"].keys()): del variable["Attr"][vattr] # fix valid_range == "-1e+35,1e+35" if "valid_range" in variable["Attr"]: valid_range = variable["Attr"]["valid_range"] if valid_range == "-1e+35,1e+35": d = numpy.ma.min(variable["Data"]) mn = pfp_utils.round2significant(d, 4, direction='down') d = numpy.ma.max(variable["Data"]) mx = pfp_utils.round2significant(d, 4, direction='up') variable["Attr"]["valid_range"] = repr(mn) + "," + repr(mx) pfp_utils.CreateVariable(ds, variable) return
def rpLL_plot(pd, ds, output, drivers, target, l6_info, si=0, ei=-1): """ Plot the results of the Lasslop run. """ iel = l6_info["ERUsingLasslop"] ieli = l6_info["ERUsingLasslop"]["info"] ielo = l6_info["ERUsingLasslop"]["outputs"] # get a local copy of the datetime series if ei == -1: dt = ds.series['DateTime']['Data'][si:] else: dt = ds.series['DateTime']['Data'][si:ei + 1] xdt = numpy.array(dt) #Hdh, f, a = pfp_utils.GetSeriesasMA(ds, 'Hdh', si=si, ei=ei) Hdh = numpy.array( [d.hour + (d.minute + d.second / float(60)) / float(60) for d in xdt]) # get the observed and modelled values obs, f, a = pfp_utils.GetSeriesasMA(ds, target, si=si, ei=ei) mod, f, a = pfp_utils.GetSeriesasMA(ds, output, si=si, ei=ei) # make the figure if iel["gui"]["show_plots"]: plt.ion() else: plt.ioff() fig = plt.figure(pd["fig_num"], figsize=(13, 8)) fig.clf() fig.canvas.set_window_title(target + " (LL): " + pd["startdate"] + " to " + pd["enddate"]) plt.figtext(0.5, 0.95, pd["title"], ha='center', size=16) # XY plot of the diurnal variation rect1 = [0.10, pd["margin_bottom"], pd["xy_width"], pd["xy_height"]] ax1 = plt.axes(rect1) # get the diurnal stats of the observations mask = numpy.ma.mask_or(obs.mask, mod.mask) obs_mor = numpy.ma.array(obs, mask=mask) dstats = pfp_utils.get_diurnalstats(xdt, obs_mor, ieli) ax1.plot(dstats["Hr"], dstats["Av"], 'b-', label="Obs") # get the diurnal stats of all predictions dstats = pfp_utils.get_diurnalstats(xdt, mod, ieli) ax1.plot(dstats["Hr"], dstats["Av"], 'r-', label="LL(all)") mod_mor = numpy.ma.masked_where(numpy.ma.getmaskarray(obs) == True, mod, copy=True) dstats = pfp_utils.get_diurnalstats(xdt, mod_mor, ieli) ax1.plot(dstats["Hr"], dstats["Av"], 'g-', label="LL(obs)") plt.xlim(0, 24) plt.xticks([0, 6, 12, 18, 24]) ax1.set_ylabel(target) ax1.set_xlabel('Hour') ax1.legend(loc='upper right', frameon=False, prop={'size': 8}) # XY plot of the 30 minute data rect2 = [0.40, pd["margin_bottom"], pd["xy_width"], pd["xy_height"]] ax2 = plt.axes(rect2) ax2.plot(mod, obs, 'b.') ax2.set_ylabel(target + '_obs') ax2.set_xlabel(target + '_LL') # plot the best fit line coefs = numpy.ma.polyfit(numpy.ma.copy(mod), numpy.ma.copy(obs), 1) xfit = numpy.ma.array([numpy.ma.min(mod), numpy.ma.max(mod)]) yfit = numpy.polyval(coefs, xfit) r = numpy.ma.corrcoef(mod, obs) ax2.plot(xfit, yfit, 'r--', linewidth=3) eqnstr = 'y = %.3fx + %.3f, r = %.3f' % (coefs[0], coefs[1], r[0][1]) ax2.text(0.5, 0.875, eqnstr, fontsize=8, horizontalalignment='center', transform=ax2.transAxes) # write the fit statistics to the plot numpoints = numpy.ma.count(obs) numfilled = numpy.ma.count(mod) - numpy.ma.count(obs) diff = mod - obs bias = numpy.ma.average(diff) ielo[output]["results"]["Bias"].append(bias) rmse = numpy.ma.sqrt(numpy.ma.mean((obs - mod) * (obs - mod))) plt.figtext(0.725, 0.225, 'No. points') plt.figtext(0.825, 0.225, str(numpoints)) ielo[output]["results"]["No. points"].append(numpoints) plt.figtext(0.725, 0.200, 'No. filled') plt.figtext(0.825, 0.200, str(numfilled)) plt.figtext(0.725, 0.175, 'Slope') plt.figtext(0.825, 0.175, str(pfp_utils.round2significant(coefs[0], 4))) ielo[output]["results"]["m_ols"].append(coefs[0]) plt.figtext(0.725, 0.150, 'Offset') plt.figtext(0.825, 0.150, str(pfp_utils.round2significant(coefs[1], 4))) ielo[output]["results"]["b_ols"].append(coefs[1]) plt.figtext(0.725, 0.125, 'r') plt.figtext(0.825, 0.125, str(pfp_utils.round2significant(r[0][1], 4))) ielo[output]["results"]["r"].append(r[0][1]) plt.figtext(0.725, 0.100, 'RMSE') plt.figtext(0.825, 0.100, str(pfp_utils.round2significant(rmse, 4))) ielo[output]["results"]["RMSE"].append(rmse) var_obs = numpy.ma.var(obs) ielo[output]["results"]["Var (obs)"].append(var_obs) var_mod = numpy.ma.var(mod) ielo[output]["results"]["Var (LL)"].append(var_mod) ielo[output]["results"]["Var ratio"].append(var_obs / var_mod) ielo[output]["results"]["Avg (obs)"].append(numpy.ma.average(obs)) ielo[output]["results"]["Avg (LL)"].append(numpy.ma.average(mod)) # time series of drivers and target ts_axes = [] rect = [ pd["margin_left"], pd["ts_bottom"], pd["ts_width"], pd["ts_height"] ] ts_axes.append(plt.axes(rect)) #ts_axes[0].plot(xdt,obs,'b.',xdt,mod,'r-') ts_axes[0].scatter(xdt, obs, c=Hdh) ts_axes[0].plot(xdt, mod, 'r-') plt.axhline(0) ts_axes[0].set_xlim(xdt[0], xdt[-1]) TextStr = target + '_obs (' + ds.series[target]['Attr']['units'] + ')' ts_axes[0].text(0.05, 0.85, TextStr, color='b', horizontalalignment='left', transform=ts_axes[0].transAxes) TextStr = output + '(' + ds.series[output]['Attr']['units'] + ')' ts_axes[0].text(0.85, 0.85, TextStr, color='r', horizontalalignment='right', transform=ts_axes[0].transAxes) for ThisOne, i in zip(drivers, list(range(1, pd["nDrivers"] + 1))): this_bottom = pd["ts_bottom"] + i * pd["ts_height"] rect = [ pd["margin_left"], this_bottom, pd["ts_width"], pd["ts_height"] ] ts_axes.append(plt.axes(rect, sharex=ts_axes[0])) data, flag, attr = pfp_utils.GetSeriesasMA(ds, ThisOne, si=si, ei=ei) data_notgf = numpy.ma.masked_where(flag != 0, data) data_gf = numpy.ma.masked_where(flag == 0, data) ts_axes[i].plot(xdt, data_notgf, 'b-') ts_axes[i].plot(xdt, data_gf, 'r-') plt.setp(ts_axes[i].get_xticklabels(), visible=False) TextStr = ThisOne + '(' + ds.series[ThisOne]['Attr']['units'] + ')' ts_axes[i].text(0.05, 0.85, TextStr, color='b', horizontalalignment='left', transform=ts_axes[i].transAxes) # save a hard copy of the plot sdt = xdt[0].strftime("%Y%m%d") edt = xdt[-1].strftime("%Y%m%d") if not os.path.exists(ieli["plot_path"]): os.makedirs(ieli["plot_path"]) figname = ieli["plot_path"] + pd["site_name"].replace( " ", "") + "_LL_" + pd["label"] figname = figname + "_" + sdt + "_" + edt + '.png' fig.savefig(figname, format='png') # draw the plot on the screen if iel["gui"]["show_plots"]: plt.draw() pfp_utils.mypause(0.5) plt.ioff() else: plt.close(fig) plt.ion()