def plot_obs_freq(predictor_matrix, code): coastline = mv.mcoast(map_coastline_thickness=2, map_boundaries="on", map_coastline_colour="chestnut") symbol = mv.msymb( legend="on", symbol_type="marker", symbol_table_mode="on", symbol_outline="on", symbol_min_table=[1, 2, 5, 10, 15, 20, 25, 30], symbol_max_table=[2, 5, 10, 15, 20, 25, 30, 100000], symbol_colour_table=[ "RGB(0.7020,0.7020,0.7020)", "RGB(0.4039,0.4039,0.4039)", "blue", "RGB(0.4980,1.0000,0.0000)", "RGB(1.0000,0.8549,0.0000)", "orange", "red", "magenta", ], symbol_marker_table=15, symbol_height_table=0.3, ) legend = mv.mlegend( legend_text_font="arial", legend_text_font_size=0.35, legend_entry_plot_direction="row", legend_box_blanking="on", legend_entry_text_width=50, ) title = mv.mtext( text_line_count=4, text_line_1= "OBS Frequency", # To sostitute with "FE" values when relevant. text_line_2=f"WT Code = {code}", text_line_4=" ", text_font="arial", text_font_size=0.4, ) df = predictor_matrix[["LonOBS", "LatOBS", "OBS"]] grouped_df = df.groupby(["LatOBS", "LonOBS"], as_index=False).count() geo = mv.create_geo(len(grouped_df), "xyv") geo = mv.set_latitudes(geo, grouped_df["LatOBS"].to_numpy(dtype=np.float)) geo = mv.set_longitudes(geo, grouped_df["LonOBS"].to_numpy(dtype=np.float)) geo = mv.set_values(geo, grouped_df["OBS"].to_numpy(dtype=np.float)) with NamedTemporaryFile(delete=False, suffix=".pdf") as pdf: pdf_obj = mv.pdf_output(output_name=pdf.name.replace(".pdf", "")) mv.setoutput(pdf_obj) mv.plot(coastline, symbol, legend, title, geo) return pdf.name
def plot_std(predictor_matrix, code): coastline = mv.mcoast(map_coastline_thickness=2, map_boundaries="on", map_coastline_colour="chestnut") symbol = mv.msymb( legend="on", symbol_type="marker", symbol_table_mode="on", symbol_outline="on", symbol_min_table=[0, 0.0001, 0.5, 1, 2, 5], symbol_max_table=[0.0001, 0.5, 1, 2, 5, 1000], symbol_colour_table=[ "RGB(0.7020,0.7020,0.7020)", "RGB(0.2973,0.2973,0.9498)", "RGB(0.1521,0.6558,0.5970)", "RGB(1.0000,0.6902,0.0000)", "red", "RGB(1.0000,0.0000,1.0000)", ], symbol_marker_table=15, symbol_height_table=0.3, ) legend = mv.mlegend( legend_text_font="arial", legend_text_font_size=0.35, legend_entry_plot_direction="row", legend_box_blanking="on", legend_entry_text_width=50, ) error = "FER" if "FER" in predictor_matrix.columns else "FE" title = mv.mtext( text_line_count=4, text_line_1=f"{error} Standard Deviation", text_line_2=f"WT Code = {code}", text_line_4=" ", text_font="arial", text_font_size=0.4, ) df = predictor_matrix[["LonOBS", "LatOBS", error]] grouped_df = df.groupby(["LatOBS", "LonOBS"])[error].mean().reset_index() geo = mv.create_geo(len(grouped_df), "xyv") geo = mv.set_latitudes(geo, grouped_df["LatOBS"].to_numpy(dtype=np.float)) geo = mv.set_longitudes(geo, grouped_df["LonOBS"].to_numpy(dtype=np.float)) geo = mv.set_values(geo, grouped_df[error].to_numpy(dtype=np.float)) with NamedTemporaryFile(delete=False, suffix=".pdf") as pdf: pdf_obj = mv.pdf_output(output_name=pdf.name.replace(".pdf", "")) mv.setoutput(pdf_obj) mv.plot(coastline, symbol, legend, title, geo) return pdf.name
def plot_avg(predictor_matrix, code): coastline = mv.mcoast(map_coastline_thickness=2, map_boundaries="on", map_coastline_colour="chestnut") symbol = mv.msymb( legend="on", symbol_type="marker", symbol_table_mode="on", symbol_outline="on", symbol_min_table=[-1, -0.25, 0.25, 2], symbol_max_table=[-0.025, 0.25, 2, 1000], symbol_colour_table=[ "RGB(0.0000,0.5490,0.1882)", "black", "RGB(1.0000,0.6902,0.0000)", "red", ], symbol_marker_table=15, symbol_height_table=0.3, ) legend = mv.mlegend( legend_text_font="arial", legend_text_font_size=0.35, legend_entry_plot_direction="row", legend_box_blanking="on", legend_entry_text_width=50, ) error = "FER" if "FER" in predictor_matrix.columns else "FE" title = mv.mtext( text_line_count=4, text_line_1=f"{error} Mean", text_line_2=f"WT Code = {code}", text_line_4=" ", text_font="arial", text_font_size=0.4, ) df = predictor_matrix[["LonOBS", "LatOBS", error]] grouped_df = df.groupby(["LatOBS", "LonOBS"])[error].mean().reset_index() geo = mv.create_geo(len(grouped_df), "xyv") geo = mv.set_latitudes(geo, grouped_df["LatOBS"].to_numpy(dtype=np.float)) geo = mv.set_longitudes(geo, grouped_df["LonOBS"].to_numpy(dtype=np.float)) geo = mv.set_values(geo, grouped_df[error].to_numpy(dtype=np.float)) return plot_geo(geo, coastline, symbol, legend, title)
def plot_cdf(*args, location=None, title_font_size=0.4, x_range=None): """ Plot CDF curve """ # check x range x_range = [] if x_range is None else x_range if x_range and len(x_range) not in [2, 3]: raise Exception( f"plot_cdf: invalid x_range specified. Format [x_min, x_max, [x_tick]]" ) if len(x_range) == 2 and x_range[1] <= x_range[0]: raise Exception( f"plot_cdf: invalid x_range specified. x_min={x_range[0]} >= x_max={x_range[1]}" ) layers = _make_layers(*args, form_layout=False) desc = [] cdf_data = [] cdf_label = [] title_data = [] y_values = np.arange(0, 101) plot_units = "" units_scaler = None # compute the cdf for each input layer for layer in layers: if isinstance(layer["data"], mv.Fieldset): # we assume each field has the same units and paramId if plot_units == "": meta = mv.grib_get(layer["data"][0], ["units", "paramId"]) if meta and len(meta[0]) == 2: meta = {"units": meta[0][0], "paramId": meta[0][1]} units_scaler = Scaling.find_item(meta) if units_scaler is not None: plot_units = units_scaler.to_units else: plot_units = meta.get("units", "") # determine ens number and steps members = layer["data"]._unique_metadata("number") steps = layer["data"]._unique_metadata("step") # print(f"members={members}") # ens forecast if len(members) > 1: for step in steps: v = layer["data"].select(step=step) v = mv.nearest_gridpoint(v, location) # print(f"step={step}") x = np.percentile(v, y_values) if units_scaler is not None: x = units_scaler.scale_value(x) # print(f" x={x}") cdf_data.append(x) cdf_label.append(layer["data"].label + f" +{step}h") # deterministic forecast else: raise Exception(f"plot_cds: only ENS data accepted as input!") title_data.append(layer["data"]) # define x axis params if not x_range: x_tick, x_min, x_max = Layout.compute_axis_range( _y_min(cdf_data), _y_max(cdf_data)) elif len(x_range) == 2: x_min = x_range[0] x_max = x_range[1] x_tick, _, _ = Layout.compute_axis_range(x_min, x_max) elif len(x_range) == 3: x_min = x_range[0] x_max = x_range[1] x_tick = x_range[2] else: raise Exception(f"plot_cdf: invalid x_range={x_range} specified!") # print(f"x_tick={x_tick} x_min={x_min} x_max={x_max}") x_title = f"[{plot_units}]" # define y axis params y_min = 0 y_max = 100 y_tick = 10 y_title = "Percentage [%]" # define the view view = Layout().build_xy(x_min, x_max, y_min, y_max, x_tick, y_tick, x_title, y_title) desc.append(view) # define curves line_colours = [ "red", "blue", "green", "black", "cyan", "evergreen", "gold", "pink", ] line_styles = ["solid", "dash", "dotted"] colour_idx = -1 style_idx = 0 for i, d in enumerate(cdf_data): vis = mv.input_visualiser(input_x_values=d, input_y_values=y_values) colour_idx = (colour_idx + 1) % len(line_colours) vd = mv.mgraph( graph_type="curve", graph_line_colour=line_colours[colour_idx], graph_line_thickness=3, legend_user_text=cdf_label[i], legend="on", ) desc.append(vis) desc.append(vd) # add title title = Title(font_size=title_font_size) t = title.build_cdf(title_data) if t is not None: desc.append(t) # add legend legX = 3.5 legY = 14 # Legend legend = mv.mlegend( legend_display_type="disjoint", legend_entry_plot_direction="column", legend_text_composition="user_text_only", legend_border="on", legend_border_colour="black", legend_box_mode="positional", legend_box_x_position=legX, legend_box_y_position=legY, legend_box_x_length=4, legend_box_y_length=3, legend_text_font_size=0.35, legend_box_blanking="on", ) desc.append(legend) mv.plot(desc, animate=False)
def plot_rmse(*args, ref=None, area=None, title_font_size=0.4, y_max=None): """ Plot RMSE curve """ desc = [] if not isinstance(ref, mv.Fieldset): raise Exception(f"Missing or invalid ref argument!") layers = _make_layers(*args, form_layout=False) # compute the rmse for each input layer data = [] # list of tuples rmse_data = [] title_data = [] has_ef = False for layer in layers: if isinstance(layer["data"], mv.Fieldset): # determine ens number members = layer["data"]._unique_metadata("number") # print(f"members={members}") # ens forecast if len(members) > 1: if has_ef: raise Exception( "Only one ENS fieldset can be used in plot_rmse()!") has_ef = True em_d = None # ens mean for m in members: pf_d = layer["data"].select(number=m) ref_d, pf_d = _prepare_grid(ref, pf_d) data.append(("cf" if m == "0" else "pf", layer["data"])) rmse_data.append(mv.sqrt(mv.average((pf_d - ref_d)**2))) em_d = pf_d if em_d is None else em_d + pf_d # compute rmse for ens mean data.append(("em", layer["data"])) rmse_data.append( mv.sqrt(mv.average((em_d / len(members) - ref_d)**2))) # deterministic forecast else: ref_d, dd = _prepare_grid(ref, layer["data"]) data.append(("fc", layer["data"])) rmse_data.append(mv.sqrt(mv.average((dd - ref_d)**2))) title_data.append(layer["data"]) # define x axis params dates = ref.valid_date() x_min = dates[0] x_max = dates[-1] x_tick = 1 x_title = "" # define y axis params y_min = 0 if y_max is None: y_tick, _, y_max = Layout.compute_axis_range(0, _y_max(rmse_data)) else: y_tick, _, _ = Layout.compute_axis_range(0, y_max) y_title = "RMSE [" + mv.grib_get_string(ref[0], "units") + "]" # print(f"y_tick={y_tick} y_max={y_max}") # define the view view = Layout().build_rmse(x_min, x_max, y_min, y_max, x_tick, y_tick, x_title, y_title) desc.append(view) # define curves ef_label = {"cf": "ENS cf", "pf": "ENS pf", "em": "ENS mean"} ef_colour = {"cf": "black", "pf": "red", "em": "kelly_green"} fc_colour = [ "red", "blue", "green", "black", "cyan", "evergreen", "gold", "pink" ] if has_ef: fc_colour = [x for x in fc_colour if x not in list(ef_colour.values())] pf_label_added = False colour_idx = -1 legend_item_count = 0 for i, d in enumerate(rmse_data): vis = mv.input_visualiser(input_x_type="date", input_date_x_values=dates, input_y_values=d) vd = {"graph_type": "curve"} line_colour = "black" line_width = 1 if data[i][0] == "fc": line_width = 3 colour_idx = (colour_idx + 1) % len(fc_colour) line_colour = fc_colour[colour_idx] # print(f"label={data[i][1][0].label}") vd["legend_user_text"] = data[i][1].label vd["legend"] = "on" legend_item_count += 1 elif data[i][0] == "pf": line_width = 1 line_colour = ef_colour["pf"] if not pf_label_added: pf_label_added = True vd["legend_user_text"] = ef_label.get("pf", "") vd["legend"] = "on" legend_item_count += 1 elif data[i][0] in ["cf", "em"]: line_width = 3 line_colour = ef_colour[data[i][0]] vd["legend_user_text"] = ef_label.get(data[i][0], "") vd["legend"] = "on" legend_item_count += 1 vd["graph_line_colour"] = line_colour vd["graph_line_thickness"] = line_width desc.append(vis) desc.append(mv.mgraph(**vd)) # add title title = Title(font_size=title_font_size) t = title.build_rmse(ref, title_data) if t is not None: desc.append(t) # add legend leg_left = 3.5 # legY = 14 leg_height = legend_item_count * (0.35 + 0.5) + (legend_item_count + 1) * 0.1 leg_bottom = 17.5 - leg_height # Legend legend = mv.mlegend( legend_display_type="disjoint", legend_entry_plot_direction="column", # "row", legend_text_composition="user_text_only", legend_border="on", legend_border_colour="black", legend_box_mode="positional", legend_box_x_position=leg_left, legend_box_y_position=leg_bottom, legend_box_x_length=4, legend_box_y_length=leg_height, legend_text_font_size=0.35, legend_box_blanking="on", ) desc.append(legend) mv.plot(desc, animate=False)
def plot_diff_maps( *args, view=None, area=None, overlay=None, diff_style=None, pos_values=None, title_font_size=0.4, legend_font_size=0.35, frame=-1, animate="auto", ): """ Plot difference maps """ # handle default arguments pos_values = [] if pos_values is None else pos_values diff_style = [] if diff_style is None else diff_style if not isinstance(diff_style, list): diff_style = [diff_style] # define the view view = _make_view(view, area, plot_type="diff") # build the layout dw = Layout().build_diff(view=view) data = {} vd = {} # the positional arguments has the following order: # data1, visdef1.1 visdef1.2 ... data2, visdef2.1, visdef2.2 ... # the visdef objects are optional! assert len(args) >= 2 assert isinstance(args[0], mv.Fieldset) layers = _make_layers(*args, form_layout=False) assert len(layers) == 2 # LOG.debug(f"layers={layers}") data["0"] = layers[0]["data"] data["1"] = layers[1]["data"] vd["0"] = _make_visdef(data["0"], layers[0]["vd"]) vd["1"] = _make_visdef(data["1"], layers[1]["vd"]) # overlay data ov_data = {} ov_vd = {} if overlay is not None: # single value, list or tuple: a data item that will be plotted into each map if not isinstance(overlay, dict): if isinstance(overlay, tuple): ov_args = list(overlay) else: ov_args = [overlay ] if not isinstance(overlay, list) else overlay # print(ov_args) ov_layers = _make_layers(*ov_args, form_layout=False) # print(ov_layers) assert len(ov_layers) == 1 d = ov_layers[0]["data"] if isinstance(d, Track): d = d.build(style=ov_layers[0]["vd"]) for k in ["d", "0", "1"]: ov_data[k] = d ov_vd[k] = _make_visdef(d, ov_layers[0]["vd"]) else: pass # LOG.debug("len_0={}".format(len(data["0"]))) # LOG.debug("len_1={}".format(len(data["0"]))) # the plot description desc = [] title = Title(font_size=title_font_size) # compute diff data["0"], data["1"] = _prepare_grid(data["0"], data["1"]) data["d"] = data["0"] - data["1"] data["d"]._ds_param_info = data["1"].ds_param_info if data["0"].label and data["1"].label: data["d"]._label = "{}-{}".format(data["0"].label, data["1"].label) else: data["d"]._label = "" vd["d"] = _make_visdef(data["d"], diff_style, plot_type="diff", pos_values=pos_values) # LOG.debug("len_d={}".format(len(data["d"]))) for i, k in enumerate(["d", "0", "1"]): desc.append(dw[i]) if frame == -1: d = data[k] else: d = data[k][frame] d._ds_param_info = data[k]._ds_param_info d._label = data[k]._label desc.append(d) if vd[k]: desc.append(vd[k]) # add overlay if k in ov_data: if isinstance(ov_data[k], mv.Fieldset): dd = ov_data[k] if frame == -1 else ov_data[k][frame] else: dd = ov_data[k] desc.append(dd) if k in ov_vd and ov_vd[k]: desc.append(ov_vd[k]) t = title.build(data[k]) legend = mv.mlegend(legend_text_font_size=legend_font_size) desc.append(legend) desc.append(t) # print(desc) return mv.plot(desc, animate=animate)
def plot_maps( *args, layout=None, view=None, area=None, use_eccharts=False, title_font_size=0.4, legend_font_size=0.35, frame=-1, animate="auto", ): """ Plot maps with generic contents """ # in the positional arguments we have two options: # 1. we only have non-list items. They belong to a single plot page. # 2. we only have list items. Each list item defines a separate plot page. plot_def = _make_layers(*args, form_layout=True) # collect the data items data_items = [] for i, sc_def in enumerate(plot_def): for layer in sc_def: data = layer["data"] if isinstance(data, mv.Fieldset): data_items.append(data[0]) # define the view view = _make_view(view, area, data=data_items) # build the layout num_plot = len(plot_def) dw = Layout().build_grid(page_num=num_plot, layout=layout, view=view) # the plot description desc = [] title = Title(font_size=title_font_size) # build each scene data_id = ("d0", 0) for i, sc_def in enumerate(plot_def): desc.append(dw[i]) # define layers data_items = [] use_data_id = (sum([ 1 for layer in sc_def if isinstance(layer["data"], mv.Fieldset) ]) > 1) for layer in sc_def: data = layer["data"] vd = layer["vd"] if isinstance(data, mv.Fieldset): if use_data_id: data_items.append((data, data_id[0])) else: data_items.append(data) if frame != -1: if data.ds_param_info.scalar: data = data[frame] else: data = data[2 * frame:2 * frame + 2] elif isinstance(data, Track): data = data.build(style=vd) desc.append(data) if isinstance(data, mv.Fieldset): vd = _make_visdef( data, vd, use_eccharts=use_eccharts, style_db="param", plot_type="map", data_id=data_id[0] if use_data_id else None, ) if vd: desc.extend(vd) data_id = (f"d{data_id[1]+1}", data_id[1] + 1) if data_items: legend = mv.mlegend(legend_text_font_size=legend_font_size) desc.append(legend) t = title.build(data_items) # LOG.debug(f"t={t}") desc.append(t) for i in range(len(plot_def), len(dw)): desc.append(dw[i]) LOG.debug(f"desc={desc}") return mv.plot(desc, animate=animate)