def quantPeriod(varname=None, datasets=None, fit=None, quantiles=None, name=None, units='years', sampling_period=1, asVar=True, lmean=None, lmedian=None, lbootstrap=False, percentiles=(0.025,0.975), lvar=False, reference=0, bootstrap_axis='bootstrap', lsample=False, sample_axis='station', **kwargs): ''' Compute the return periods of events with intensities equal to the given quantiles in the reference sample. Confidence intervals can be estimated from bootstrapping or sample distributions. The data is returned as a variable object with axes for quantiles, datasets, and distribution percentiles; quantiles are converted to return periods (years, by default). ''' # input requirements if not isinstance(fit, Ensemble): raise TypeError(fit) if not all([isinstance(ds, Dataset) for ds in fit]): raise TypeError(fit) # cast quantiles as array quantiles = np.asarray(quantiles) # select datasets if datasets is not None: if not isinstance(datasets,(tuple,list)): raise TypeError(datasets) fit = selectDataset(fit, datasets) assert datasets == fit.name else: datasets = fit.name if lsample and lmean is None: lmean = True # show mean instead of "true fit" if lsample and lmedian is None: lmedian = False # don't show median # compute references quantiles if isinstance(reference,(int,np.integer)): reference = fit[reference].name if not isinstance(reference,str): raise TypeError(reference) if lsample: refvals = checkVarlist(fit[reference], varname=varname, ndim=2, support=quantiles, method='ppf')[0] refvals = refvals.mean(axis=sample_axis, asVar=False) else: refvals = checkVarlist(fit[reference], varname=varname, ndim=1, support=quantiles, method='ppf')[0][:] # just get values # compute qunatiles corresponding to reference quantiles if ( lsample and any(ds.hasAxis(sample_axis, lany=True) for ds in fit) or lbootstrap and any(ds.hasAxis(bootstrap_axis) for ds in fit) ): ciaxis = bootstrap_axis if lbootstrap else sample_axis # compute confidence itnervals civars = checkVarlist(fit, varname=varname, ndim=2, support=refvals, method='cdf', bootstrap_axis=None) q = (percentiles[0],0.5,percentiles[1]) if lmedian and lsample else percentiles # median is a percentile if lmean: qvars = [civar.mean(axis=sample_axis, asVar=True,) for civar in civars] civars = [civar.percentile(q=q, axis=ciaxis, asVar=True,) for civar in civars] if lmedian: qvars = [civar(percentile=0.5,) for civar in civars] lovars = [civar(percentile=percentiles[0],) for civar in civars] hivars = [civar(percentile=percentiles[1],) for civar in civars] if lbootstrap or not lsample: # get the one true realization qvars = checkVarlist(fit, varname=varname, ndim=1, support=refvals, method='cdf', bootstrap_axis=bootstrap_axis) # returns a list of variables containing the quantile values if lbootstrap or lsample: # prepend the true/mean value to CI intervals (percentile axis) pax = Axis(coord=np.asarray((-1,)+percentiles), name='percentile', units='') tmplist = [] for qvar,lovar,hivar in zip(qvars,lovars,hivars): tmp = concatVars((qvar,lovar,hivar), axis=pax, asVar=True, name=qvar.name, units=qvar.units, varatts=qvar.atts, lcheckAxis=True, lensembleAxis=True) tmplist.append(tmp) qvars = tmplist # new qvar list with percentiles / CI's # concatenate experiments by creating new axis if asVar: # create experiment axis expax = Axis(coord=np.arange(len(datasets)), name='experiment', units='#', atts=dict(datasets=datasets)) # concat variables name = name or varname+'_periods' quantvar = concatVars(qvars, axis=expax, asVar=True, name=name, units=units, lcheckAxis=True, lensembleAxis=True) quantvar.data_array = convQuant(quantvar.data_array, smpl_prd=sampling_period, lround=True) # rename "_bins" variable for axis in quantvar.axes: if axis.name[-5:] == '_bins': axis.coord = convQuant(quantiles, smpl_prd=sampling_period, lround=True) axis.name = 'quantile'; axis.units = units else: quantvar = {dataset:qvar for dataset,qvar in zip(datasets,qvars)} # return # N.B.: the true/mean/median value is the first one along the percentile axis (percentile = -1) return quantvar
def quantPlot(axes=None, varname=None, datasets=None, fit=None, scl=None, legend=True, quantiles=None, shape_name=None, stnset_name=None, ylim=None, xlim=None, ylabel=True, xlabel=True, xticks=True, yticks=True, axtitle=None, lbootstrap=False, percentiles=(0.025,0.975), band_vars=None, lmedian=None, median_fmt='', lrescaleBand=False, sampling_period=1, lmean=None, mean_fmt='', lvar=False, lvarBand=False, lrescale=False, reference=0, bootstrap_axis='bootstrap', lsample=False, sample_axis='station', annotation=None, defaults=None, **kwargs): ''' Generate an EVA quantile plot with annotations in a single axes, including (re-)scaled curves. The y-axis is labeled with return periods and specific quantiles can be marked by vertical lines. ''' # cast quantiles as array quantiles = np.asarray(quantiles) if quantiles else None # y-limits for upper and lower percentiles if ylim is None: if quantiles is not None: if np.min(quantiles) > 0.5: ylim = (0.95,1.01) else: ylim = (-0.01,0.065) else: ylim = (0.95,1.01) bins = ylim+(200,) if ylim[1] >= 1: axes.addHline(1, color='k', alpha=0.5) # mark one line if ylim[0] <= 0: axes.addHline(0, color='k', alpha=0.5) # mark zero line # get reasonable x-limits for variables based on region if xlim is None: if stnset_name is not None: xlim = annotation[stnset_name].get(varname,None) elif shape_name is not None: xlim = annotation[shape_name].get(varname,None) elif varname in defaults: xlim = defaults.get(varname,None) else: xlim = axes.get_xlim() # select datasets if datasets is not None: if not isinstance(datasets,(tuple,list)): raise TypeError(datasets) fit = selectDataset(fit, datasets) scl = selectDataset(scl, datasets) if lsample and lmean is None: lmean = True # show mean instead of "true fit" if lsample and lmedian is None: lmedian = False # don't show median # generate quantile plot if lsample and any(ds.hasAxis(sample_axis, lany=True) for ds in fit): plts = axes.samplePlot(fit,varname, support=bins, method='ppf', linewidth=1.25, title=axtitle, flipxy=True, llabel=True, legend=legend, percentiles=percentiles, sample_axis=sample_axis, bootstrap_axis=bootstrap_axis, band_vars=band_vars, xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, lmedian=lmedian, median_fmt=median_fmt, lmean=lmean, mean_fmt=mean_fmt, lsmooth=False, bandalpha=0.25, **kwargs) elif lbootstrap and any(ds.hasAxis(bootstrap_axis) for ds in fit): plts = axes.bootPlot(fit,varname, support=bins, method='ppf', linewidth=1.25, title=axtitle, flipxy=True, llabel=True, legend=legend, percentiles=percentiles, band_vars=band_vars, xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, lmedian=lmedian, median_fmt=median_fmt, lmean=lmean, mean_fmt=mean_fmt, lvar=lvar, lvarBand=lvarBand, lsmooth=False, bandalpha=0.25, **kwargs) # N.B.: smoothing causes (resolution-dependent) artifacts near the limit (1 or 0) else: plts = axes.linePlot(fit, varname, support=bins, method='ppf', linewidth=1.25, title=axtitle, xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, flipxy=True, llabel=True, legend=legend, **kwargs) # add percentile lines if quantiles is not None: iref = fit.idkeys.index(reference) if isinstance(reference,str) else reference if lsample: quants = checkVarlist(fit[iref], varname=varname, ndim=2, support=quantiles, method='ppf')[0].mean(asVar=True) else: quants = checkVarlist(fit[iref], varname=varname, ndim=1, support=quantiles, method='ppf')[0] qvals = quants.data_array * quants.plot.scalefactor + quants.plot.offset axes.addVline(qvals, color=plts[iref].get_color(), alpha=0.5) # linestyle=plts[iref].get_linestyle() if lrescale and scl: # plot scaled quantile distributions if lsample and any(ds.hasAxis(sample_axis, lany=True) for ds in scl): plts = axes.samplePlot(scl,varname, support=bins, method='ppf', linewidth=1., mean_fmt='--', title=None, flipxy=True, llabel=False, legend=legend, percentiles=percentiles if lrescaleBand else None, band_vars=band_vars, sample_axis=sample_axis, bootstrap_axis=bootstrap_axis, xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, lmedian=lmedian, median_fmt='--', lmean=lmean, #mean_fmt=mean_fmt, lsmooth=False, bandalpha=0.25, **kwargs) elif lbootstrap and any(ds.hasAxis(bootstrap_axis) for ds in scl): # bandalf = kwargs.pop('bandalhpa',0.5) * 0.7 plts = axes.bootPlot(scl,varname, support=bins, method='ppf', percentiles=percentiles if lrescaleBand else None, linewidth=1., lineformat='--', bandalpha=0.25, flipxy=True, lmedian=lmedian, median_fmt='--', xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, lmean=lmean, mean_fmt='--', lvar=lvar, lvarBand=lvarBand, band_vars=band_vars, llabel=False, lsmooth=False, **kwargs) # N.B.: smoothing causes (resolution-dependent) artifacts near the limit (1 or 0) else: plts = axes.linePlot(scl, varname, support=bins, method='ppf', linewidth=1., linestyle='--', xlim=xlim, ylim=ylim, ylabel=ylabel, xlabel=xlabel, xticks=xticks, yticks=yticks, flipxy=True, llabel=False, legend=None, **kwargs) # add percentile lines for scaled distributions if quantiles is not None: iref = scl.idkeys.index(reference) if isinstance(reference,str) else reference if lsample: quants = checkVarlist(scl[iref], varname=varname, ndim=2, support=quantiles, method='ppf')[0].mean(asVar=True) else: quants = checkVarlist(scl[iref], varname=varname, ndim=1, support=quantiles, method='ppf')[0] qvals = quants.data_array * quants.plot.scalefactor + quants.plot.offset axes.addVline(qvals, color=plts[iref].get_color(), alpha=0.35) # linestyle=plts[iref].get_linestyle() # convert y-tick labels to return periods yticks = ['{:3.0f}'.format(sampling_period/(1-yt)) if yt < 1 else '' for yt in axes.get_yticks().tolist()] axes.set_yticklabels(yticks) # return return plts