Note
Click here
to download the full example code
GRIB - ENS Tephigram
# (C) Copyright 2017- ECMWF.
#
# This software is licensed under the terms of the Apache Licence Version 2.0
# which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
#
# In applying this licence, ECMWF does not waive the privileges and immunities
# granted to it by virtue of its status as an intergovernmental organisation
# nor does it submit to any jurisdiction.
#
import numpy as np
import metview as mv
# read ENS data
filename = "ens_prof.grib"
if mv.exist(filename):
data = mv.read(filename)
else:
data = mv.gallery.load_dataset(filename)
# define profile location
location = [17.51, -7.04]
# the starting x coordinate of the sidebar on the right.
# Wind and dewpoint depression is plotted there.
# Do not change it!
sidebar_x_offset = 1000
# the ensemble size (perturbed members)
ens_num = 50
# filter control (cf) and perturbed (pf) forcasts
g_cf = mv.read(data=data, type="cf")
g_pf = mv.read(data=data, type="pf")
# extract thermo profile for cf
nc = mv.thermo_grib(
data=g_cf, point_extraction="nearest_gridpoint", coordinates=location
)
prof_cf = mv.thermo_data_values(nc, 0)
# extract thermo profile for pf
nc = mv.thermo_grib(
data=g_pf, point_extraction="nearest_gridpoint", coordinates=location
)
prof_pf = mv.thermo_data_values(nc, 0)
# define colours for shaded areas
t_col_outer = "RGB(1.0000,0.7922,0.7961)"
t_col_inner = "RGB(0.8863,0.0000,0.0000)"
td_col_outer = "RGB(0.8,0.9137,0.8)"
td_col_inner = "RGB(0.3882,0.7765,0.3843)"
ddep_col_outer = "RGB(0.8118,0.8902,1)"
ddep_col_inner = "RGB(0.4353,0.6314,1)"
# define colours for curves
t_col_line = "RGB(0.8706,0,0)"
td_col_line = "RGB(0,0.2784,0.007843)"
ddep_col_line = "RGB(0,0.3725,1)"
# define cf curve data
t_cf = prof_cf["t"]
td_cf = prof_cf["td"]
ddep_cf = (t_cf - td_cf) + sidebar_x_offset
# get pressure levels for t and td (from pf)
# and compute ENS mean profiles
lev_num = int(len(prof_pf["p"]) / ens_num)
p = np.empty(lev_num)
t_mean = np.empty(lev_num)
td_mean = np.empty(lev_num)
ddep_mean = np.empty(lev_num)
for i in range(len(p)):
# get pressure
p[i] = prof_pf["p"][i * ens_num]
# get t and td for all the perturbed members
idx_start = i * ens_num
idx_end = (i + 1) * ens_num - 1
t_v = prof_pf["t"][idx_start:idx_end]
td_v = prof_pf["td"][idx_start:idx_end]
# add t and td from cf
t_v = np.append(t_v, t_cf[i])
td_v = np.append(td_v, td_cf[i])
# compute means
t_mean[i] = mv.mean(t_v)
td_mean[i] = mv.mean(td_v)
ddep_mean[i] = mv.mean(t_v - td_v) + sidebar_x_offset
# compute areas (polygons) for t, td and dew point depression (ddep)
# outer area = full ENS range
# inner area = 25-75 percentile range
p_poly = np.empty(lev_num * 2)
t_poly_inner = np.empty(lev_num * 2)
t_poly_outer = np.empty(lev_num * 2)
td_poly_inner = np.empty(lev_num * 2)
td_poly_outer = np.empty(lev_num * 2)
ddep_poly_inner = np.empty(lev_num * 2)
ddep_poly_outer = np.empty(lev_num * 2)
for i in range(lev_num):
# collect t and td (pf+cf) for the given level
idx_start = i * ens_num
idx_end = (i + 1) * ens_num - 1
t_v = prof_pf["t"][idx_start:idx_end]
td_v = prof_pf["td"][idx_start:idx_end]
t_v = np.append(t_v, t_cf[i])
td_v = np.append(td_v, td_cf[i])
i_left = i
i_right = 2 * lev_num - i - 1
p_poly[i_left] = p[i]
p_poly[i_right] = p[i]
t_poly_outer[i_left] = mv.minvalue(t_v)
t_poly_outer[i_right] = mv.maxvalue(t_v)
perc = mv.percentile(t_v, [25, 75])
t_poly_inner[i_left] = perc[0]
t_poly_inner[i_right] = perc[1]
td_poly_outer[i_left] = mv.minvalue(td_v)
td_poly_outer[i_right] = mv.maxvalue(td_v)
perc = mv.percentile(td_v, [25, 75])
td_poly_inner[i_left] = perc[0]
td_poly_inner[i_right] = perc[1]
ddep_v = t_v - td_v + sidebar_x_offset
ddep_poly_outer[i_left] = mv.minvalue(ddep_v)
ddep_poly_outer[i_right] = mv.maxvalue(ddep_v)
perc = mv.percentile(ddep_v, [25, 75])
ddep_poly_inner[i_left] = perc[0]
ddep_poly_inner[i_right] = perc[1]
# generate graphic objects (areas) for the shaded areas
gr_lst = [
mv.xy_area(t_poly_outer, p_poly, t_col_outer),
mv.xy_area(t_poly_inner, p_poly, t_col_inner),
mv.xy_area(td_poly_outer, p_poly, td_col_outer),
mv.xy_area(td_poly_inner, p_poly, td_col_inner),
mv.xy_area(ddep_poly_outer, p_poly, ddep_col_outer),
mv.xy_area(ddep_poly_inner, p_poly, ddep_col_inner),
]
# generate graphic objects (curves) for the mean ENS and cf profiles
gr_lst.extend(
[
mv.xy_curve(t_mean, p, t_col_line, "solid", 4),
mv.xy_curve(td_mean, p, td_col_line, "solid", 4),
mv.xy_curve(ddep_mean, p, ddep_col_line, "solid", 4),
mv.xy_curve(t_cf, prof_cf["p"], t_col_line, "dash", 3),
mv.xy_curve(td_cf, prof_cf["p"], td_col_line, "dash", 3),
mv.xy_curve(ddep_cf, prof_cf["p"], ddep_col_line, "dash", 3),
]
)
# generate graphic object for wind profile from cf
vis = mv.input_visualiser(
input_plot_type="xy_vectors",
input_x_values=[sidebar_x_offset + 10 for i in prof_cf["p_wind"]],
input_y_values=prof_cf["p_wind"],
input_x_component_values=prof_cf["u"],
input_y_component_values=prof_cf["v"],
)
wind_plotting = mv.mwind(wind_field_type="flags", wind_flag_colour="charcoal")
gr_lst.extend([vis, wind_plotting])
# define title
title_txt = "ENS Tephigram Date: {} {} UTC Lat/Lon: {}/{} ".format(
prof_cf["date"], prof_cf["time"], prof_cf["lat"], prof_cf["lon"]
)
title = mv.mtext(text_lines=title_txt, text_font_size=0.5, text_colour="charcoal")
# define thermodynamic grid
grid = mv.mthermogrid(
thermo_isotherm_colour="RGB(0.2577,0.6364,0.5039)",
thermo_isotherm_reference_colour="blue",
thermo_dry_adiabatic_colour="grey",
thermo_dry_adiabatic_label_frequency=2,
thermo_mixing_ratio_colour="RGB(0.2577,0.6364,0.5039)",
thermo_mixing_ratio_label_colour="RGB(0.2577,0.6364,0.5039)",
thermo_mixing_ratio_label_font_size=0.4,
thermo_grid_layer_mode="foreground",
)
# define thermodynamic view
view = mv.thermoview(
type="tephigram",
minimum_temperature=-110,
maximum_temperature=30,
subpage_clipping="on",
)
# define the output plot file
mv.setoutput(mv.pdf_output(output_name="ens_tephigram"))
# generate the plot
mv.plot(view, gr_lst, grid, title)