def plot_drydown(sim_data, flux_data, met_data, name, date_range): """Plot behaviour during dry-downs. Plots rainfall, as well as Qh and Qle for obs and simulations. :sim_data: xarray dataset from a simulation :flux_data: xarray dataset from a simulation :met_data: xarray dataset from a simulation :name: model name :returns: plot filename """ year_range = [parse(d).year for d in date_range] year_range[1] += 1 year_range = ['%s-01-01' % d for d in year_range] site = pals_site_name(met_data) sns.set_palette( sns.color_palette(['#aa0000', '#ff4444', '#0000aa', '#4477ff'])) # Plot rainfall in mm Rainf = (pals_xr_to_df(met_data.sel(time=slice(*year_range)), ['Rainf']).resample('1W', how='sum') * 1000).mean() obs = (pals_xr_to_df(flux_data.sel(time=slice(*year_range)), ['Qh', 'Qle']).resample('1D')).mean() sim = (pals_xr_to_df(sim_data.sel(time=slice(*year_range)), ['Qh', 'Qle']).resample('1D')).mean() x_vals = Rainf.index.to_pydatetime() fig, ax = pl.subplots() ax.bar(x_vals, Rainf.values, width=7, color='lightblue', linewidth=0) x_vals = obs.index.to_pydatetime() for c in obs: if c == 'Qle': offset = 0 if c == 'Qh': offset = 100 ax.plot(x_vals, pd.rolling_mean(obs[c], 14) + offset, label='Obs %s + %d' % (c, offset)) ax.plot(x_vals, pd.rolling_mean(sim[c], 14) + offset, label='Sim %s + %d' % (c, offset)) ax.axvspan(parse(date_range[0]), parse(date_range[1]), color='black', alpha=0.1, zorder=-100) pl.legend(loc=0) pl.title('{n}: drydown plot at {s}'.format(n=name, s=site)) filename = '{n}_{s}_drydown_timeseries_plot.png'.format(n=name, s=site) return filename
def plot_drydown_daily_cycles(sim_data, flux_data, met_data, name, date_range): """Plot daily cycle behaviour during dry-downs. Plots rainfall, as well as Qh and Qle for obs and simulations. :sim_data: xarray dataset from a simulation :flux_data: xarray dataset from a simulation :met_data: xarray dataset from a simulation :name: model name :returns: plot filename """ d_range = [np.datetime64(parse(d)) for d in date_range] del_t = np.timedelta64(7, 'D') first_cycle = d_range[0] + [-del_t, del_t] last_cycle = d_range[1] + [-del_t, del_t] site = pals_site_name(met_data) sns.set_palette( sns.color_palette(['#aa0000', '#ff4444', '#0000aa', '#4477ff'])) fig, _ = pl.subplots(2, 1, sharey=True) periods = {0: 'start', 1: 'end'} flux_vars = list( set(['Qh', 'Qle']).intersection(list(sim_data.data_vars)).intersection( list(sim_data.data_vars))) for i, dr in enumerate([first_cycle, last_cycle]): obs_df = pals_xr_to_df(flux_data.sel(time=slice(*dr)), flux_vars) obs = obs_df.groupby(obs_df.index.time).mean() sim_df = pals_xr_to_df(sim_data.sel(time=slice(*dr)), flux_vars) sim = sim_df.groupby(sim_df.index.time).mean() x_vals = obs.index.values ax = pl.subplot(2, 1, i + 1) for c in obs: if c == 'Qle': offset = 0 if c == 'Qh': offset = 100 ax.plot(x_vals, obs[c] + offset, label='Obs %s + %d' % (c, offset)) ax.plot(x_vals, sim[c] + offset, label='Sim %s + %d' % (c, offset)) pl.title('{n}: daily cycles for {p} of drydown at {s}'.format( n=name, s=site, p=periods[i])) pl.legend(loc=0) fig.tight_layout() filename = '{n}_{s}_drydown_daily_cycles_plot.png'.format(n=name, s=site) return filename
def get_multimodel_data(site, names, variables): """Returns a DF with variable columns, time/model indices.""" data = [] for n in names: path = "model_data/{n}/{n}_{s}.nc".format(n=n, s=site) try: with xr.open_dataset(path) as ds: df = pals_xr_to_df(ds, variables) df['name'] = n # offset time indices if n == 'COLASSiB.2.0': df.index = df.index + pd.Timedelta('-30min') if n == 'ORCHIDEE.trunk_r1401': df.index = df.index + pd.Timedelta('-15min') df.set_index('name', append=True, inplace=True) data.append(df) except (OSError, RuntimeError) as e: raise Exception(path, e) df = pd.concat(data) df.columns.name = 'variable' return df
def diagnostic_plots(sim_data, flux_data, name, site=None): """Plot standard diagnostic plots for a single site :sim_data: xarray dataset :flux_data: xarray dataset :name: mode name :returns: list of paths to plots """ if site is None: site = pals_site_name(flux_data) logger.info('Running standard plots for %s at %s' % (name, site)) base_path = 'source/models/{n}'.format(n=name) rel_path = 'figures/{s}'.format(s=site) fig_path = os.path.join(base_path, rel_path) os.makedirs(fig_path, exist_ok=True) files = [] # benchmark_names = ['1lin', '2lin', '3km27'] benchmark_names = ['S_lin', 'ST_lin', 'STH_km27'] try: benchmarks = [get_benchmark(bname, site) for bname in benchmark_names] except RuntimeError as e: logger.warning("Benchmark(s) not available at {s}, skipping. {e}".format(s=site, e=e)) return sns.set_palette(sns.color_palette(['red', 'pink', 'orange', 'black', 'blue'])) # Generalise if more multi-variable plots needed metric_df = get_PLUMBER_metrics(name, site) for plot in [p_plumber_metrics, p_metric_rank_counts]: filename = plot(metric_df, name, site) rel_plot_path = save_plot(base_path, rel_path, filename) files.append(rel_plot_path) flux_vars = ['Qle', 'Qh', 'NEE'] for var in flux_vars: try: data = pd.concat([pals_xr_to_df(ds, [var]) for ds in benchmarks + [flux_data, sim_data]], axis=1) except Exception as e: logger.warning('Data missing for {v} at {s}, skipping. {e}'.format(v=var, s=site, e=e)) continue data.columns = benchmark_names + ['observed', 'modelled'] for plot in DIAGNOSTIC_PLOTS.values(): filename = plot(data, name, var, site) rel_plot_path = save_plot(base_path, rel_path, filename) files.append(rel_plot_path) return files
def get_test_data(site, met_vars, use_names, qc=False, fix_closure=True): # We use gap-filled data for the testing period, or the model fails. met_test_xr = get_met_data(site)[site] met_test = pals_xr_to_df(met_test_xr, variables=met_vars, qc=qc, name=use_names) return dict(site=site, met_vars=met_vars, fix_closure=fix_closure, met_test=met_test, met_test_xr=met_test_xr)