def _plot_inset_histogram_for_attributes_diagram( figure_object, num_examples_by_bin, bar_face_colour=DEFAULT_HISTOGRAM_FACE_COLOUR, bar_edge_colour=DEFAULT_HISTOGRAM_EDGE_COLOUR, bar_edge_width=DEFAULT_HISTOGRAM_EDGE_WIDTH): """Plots forecast histogram inset in attributes diagram. For more on the attributes diagram, see Hsu and Murphy (1986). B = number of forecast bins :param figure_object: Instance of `matplotlib.figure.Figure`. :param num_examples_by_bin: length-B numpy array with number of examples in each forecast bin. :param bar_face_colour: Colour (in any format accepted by `matplotlib.colors`) for interior of histogram bars. :param bar_edge_colour: Colour for edge of histogram bars. :param bar_edge_width: Width for edge of histogram bars. """ error_checking.assert_is_integer_numpy_array(num_examples_by_bin) error_checking.assert_is_numpy_array(num_examples_by_bin, num_dimensions=1) error_checking.assert_is_geq_numpy_array(num_examples_by_bin, 0) num_forecast_bins = len(num_examples_by_bin) error_checking.assert_is_geq(num_forecast_bins, 2) example_frequency_by_bin = (num_examples_by_bin.astype(float) / numpy.sum(num_examples_by_bin)) forecast_bin_edges = numpy.linspace(0., 1., num=num_forecast_bins + 1) forecast_bin_width = forecast_bin_edges[1] - forecast_bin_edges[0] forecast_bin_centers = forecast_bin_edges[:-1] + forecast_bin_width / 2 inset_axes_object = figure_object.add_axes([ INSET_HISTOGRAM_LEFT_EDGE, INSET_HISTOGRAM_BOTTOM_EDGE, INSET_HISTOGRAM_WIDTH, INSET_HISTOGRAM_HEIGHT ]) inset_axes_object.bar( forecast_bin_centers, example_frequency_by_bin, forecast_bin_width, color=plotting_utils.colour_from_numpy_to_tuple(bar_face_colour), edgecolor=plotting_utils.colour_from_numpy_to_tuple(bar_edge_colour), linewidth=bar_edge_width) max_y_tick_value = rounder.floor_to_nearest( 1.05 * numpy.max(example_frequency_by_bin), INSET_HISTOGRAM_Y_TICK_SPACING) num_y_ticks = 1 + int( numpy.round(max_y_tick_value / INSET_HISTOGRAM_Y_TICK_SPACING)) y_tick_values = numpy.linspace(0., max_y_tick_value, num=num_y_ticks) pyplot.xticks(INSET_HISTOGRAM_X_TICKS, axes=inset_axes_object) pyplot.yticks(y_tick_values, axes=inset_axes_object) inset_axes_object.set_xlim(0., 1.) inset_axes_object.set_ylim(0., 1.05 * numpy.max(example_frequency_by_bin))
def _predictor_name_to_face_colour(predictor_name): """Converts predictor name to face colour for bar graph. :param predictor_name: Predictor name (string). :return: face_colour: Colour as length-3 tuple. """ if predictor_name in SOUNDING_PREDICTOR_NAMES: return plotting_utils.colour_from_numpy_to_tuple(SOUNDING_COLOUR) return plotting_utils.colour_from_numpy_to_tuple(DEFAULT_FACE_COLOUR)
def _plot_inset_histogram_for_attributes_diagram(figure_object, num_examples_by_bin): """Plots forecast histogram inset in attributes diagram. For more on the attributes diagram, see Hsu and Murphy (1986). B = number of forecast bins :param figure_object: Instance of `matplotlib.figure.Figure`. :param num_examples_by_bin: length-B numpy array with number of examples in each forecast bin. """ error_checking.assert_is_integer_numpy_array(num_examples_by_bin) error_checking.assert_is_numpy_array(num_examples_by_bin, num_dimensions=1) error_checking.assert_is_geq_numpy_array(num_examples_by_bin, 0) num_forecast_bins = len(num_examples_by_bin) error_checking.assert_is_geq(num_forecast_bins, 2) example_frequency_by_bin = (num_examples_by_bin.astype(float) / numpy.sum(num_examples_by_bin)) forecast_bin_edges = numpy.linspace(0., 1., num=num_forecast_bins + 1) forecast_bin_width = forecast_bin_edges[1] - forecast_bin_edges[0] forecast_bin_centers = forecast_bin_edges[:-1] + forecast_bin_width / 2 inset_axes_object = figure_object.add_axes([ HISTOGRAM_LEFT_EDGE, HISTOGRAM_BOTTOM_EDGE, HISTOGRAM_AXES_WIDTH, HISTOGRAM_AXES_HEIGHT ]) inset_axes_object.bar( forecast_bin_centers, example_frequency_by_bin, forecast_bin_width, color=plotting_utils.colour_from_numpy_to_tuple(BAR_FACE_COLOUR), edgecolor=plotting_utils.colour_from_numpy_to_tuple(BAR_EDGE_COLOUR), linewidth=BAR_EDGE_WIDTH) max_y_tick_value = rounder.floor_to_nearest( 1.05 * numpy.max(example_frequency_by_bin), HISTOGRAM_Y_SPACING) num_y_ticks = 1 + int(numpy.round(max_y_tick_value / HISTOGRAM_Y_SPACING)) y_tick_values = numpy.linspace(0., max_y_tick_value, num=num_y_ticks) pyplot.xticks(HISTOGRAM_X_VALUES, axes=inset_axes_object) pyplot.yticks(y_tick_values, axes=inset_axes_object) inset_axes_object.set_xlim(0., 1.) inset_axes_object.set_ylim(0., 1.05 * numpy.max(example_frequency_by_bin)) inset_axes_object.set_title('Forecast histogram', fontsize=20)
def _label_bars(axes_object, y_tick_coords, y_tick_strings, significant_flags): """Labels bars in graph. J = number of bars :param axes_object: Will plot on these axes (instance of `matplotlib.axes._subplots.AxesSubplot`). :param y_tick_coords: length-J numpy array with y-coordinates of bars. :param y_tick_strings: length-J list of labels. :param significant_flags: length-J numpy array of Boolean flags. If significant_flags[i] = True, the [i]th step has a significantly different cost than the [i + 1]th step. """ this_colour = plotting_utils.colour_from_numpy_to_tuple(BAR_TEXT_COLOUR) for j in range(len(y_tick_coords)): y_tick_strings[j] = y_tick_strings[j].replace( 'Surface geopotential height', 'Orographic height') axes_object.text( 0., y_tick_coords[j], ' ' + y_tick_strings[j], color=this_colour, horizontalalignment='left', verticalalignment='center', fontweight='bold' if significant_flags[j] else 'normal', fontsize=BAR_FONT_SIZE)
def plot_storm_outlines( storm_object_table, axes_object, basemap_object, line_width=DEFAULT_POLYGON_WIDTH, line_colour=DEFAULT_POLYGON_COLOUR, line_style='solid'): """Plots all storm objects in the table (as unfilled polygons). :param storm_object_table: See doc for `storm_tracking_io.write_file`. :param axes_object: Will plot on these axes (instance of `matplotlib.axes._subplots.AxesSubplot`). :param basemap_object: Will use this object (instance of `mpl_toolkits.basemap.Basemap`) to convert between x-y and lat-long coords. :param line_width: Width of each polygon. :param line_colour: Colour of each polygon. :param line_style: Line style for each polygon. """ line_colour_tuple = plotting_utils.colour_from_numpy_to_tuple(line_colour) num_storm_objects = len(storm_object_table.index) for i in range(num_storm_objects): this_vertex_dict_latlng = polygons.polygon_object_to_vertex_arrays( storm_object_table[tracking_utils.LATLNG_POLYGON_COLUMN].values[i] ) these_x_coords_metres, these_y_coords_metres = basemap_object( this_vertex_dict_latlng[polygons.EXTERIOR_X_COLUMN], this_vertex_dict_latlng[polygons.EXTERIOR_Y_COLUMN] ) axes_object.plot( these_x_coords_metres, these_y_coords_metres, color=line_colour_tuple, linestyle=line_style, linewidth=line_width )
def plot_storm_centroids(storm_object_table, axes_object, basemap_object, marker_type=DEFAULT_CENTROID_MARKER_TYPE, marker_colour=DEFAULT_CENTROID_COLOUR, marker_size=DEFAULT_CENTROID_MARKER_SIZE): """Plots all storm centroids in the table (as markers). :param storm_object_table: See doc for `plot_storm_outlines`. :param axes_object: Same. :param basemap_object: Same. :param marker_type: Marker type for storm centroids (in any format accepted by `matplotlib.lines`). :param marker_colour: Colour for storm centroids. :param marker_size: Marker size for storm centroids. """ marker_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( marker_colour) x_coords_metres, y_coords_metres = basemap_object( storm_object_table[tracking_utils.CENTROID_LONGITUDE_COLUMN].values, storm_object_table[tracking_utils.CENTROID_LATITUDE_COLUMN].values) axes_object.plot(x_coords_metres, y_coords_metres, linestyle='None', marker=marker_type, markerfacecolor=marker_colour_tuple, markeredgecolor=marker_colour_tuple, markersize=marker_size, markeredgewidth=0)
def plot_bootstrapped_reliability_curve( axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, line_colour=DEFAULT_RELIABILITY_COLOUR, line_width=DEFAULT_RELIABILITY_WIDTH, perfect_line_colour=DEFAULT_PERFECT_RELIABILITY_COLOUR, perfect_line_width=DEFAULT_PERFECT_RELIABILITY_WIDTH): """Bootstrapped version of plot_reliability_curve. B = number of bins (separated by forecast probability) :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: Dictionary with the following keys, representing the bottom of the confidence interval. ci_bottom_dict['mean_forecast_by_bin']: length-B numpy array of mean forecast probabilities. ci_bottom_dict['event_frequency_by_bin']: length-B numpy array of conditional event frequencies. :param ci_mean_dict: Same but for mean of confidence interval. :param ci_top_dict: Same but for top of confidence interval. :param line_colour: Colour for reliability curve (mean of confidence interval; in any format accepted by `matplotlib.colors`). The rest of the confidence interval will be shaded with the same colour but 50% opacity. :param line_width: Line width for reliability curve (mean of confidence interval). :param perfect_line_colour: Colour of reference line (perfect reliability curve). :param perfect_line_width: Width of reference line. """ plot_reliability_curve( axes_object=axes_object, mean_forecast_by_bin=ci_mean_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], event_frequency_by_bin=ci_mean_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], line_colour=line_colour, line_width=line_width, perfect_line_colour=perfect_line_colour, perfect_line_width=perfect_line_width) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_bottom=ci_bottom_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], x_coords_top=ci_top_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_top=ci_top_dict[model_eval.EVENT_FREQ_BY_BIN_KEY]) polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(line_colour), TRANSPARENCY_FOR_CONFIDENCE_INTERVAL) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def plot_bootstrapped_performance_diagram( axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, line_colour=DEFAULT_PERFORMANCE_COLOUR, line_width=DEFAULT_PERFORMANCE_WIDTH, bias_line_colour=DEFAULT_FREQ_BIAS_COLOUR, bias_line_width=DEFAULT_FREQ_BIAS_WIDTH): """Bootstrapped version of plot_performance_diagram. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: Dictionary with the following keys, representing the bottom of the confidence interval. ci_bottom_dict['pod_by_threshold']: length-T numpy array of POD values (probability of detection). ci_bottom_dict['success_ratio_by_threshold']: length-T numpy array of success ratios. :param ci_mean_dict: Same but for mean of confidence interval. :param ci_top_dict: Same but for top of confidence interval. :param line_colour: Colour for performance curve (mean of confidence interval; in any format accepted by `matplotlib.colors`). The rest of the confidence interval will be shaded with the same colour but 50% opacity. :param line_width: Line width for performance curve (mean of confidence interval). :param bias_line_colour: Colour of contour lines for frequency bias. :param bias_line_width: Width of contour lines for frequency bias. """ plot_performance_diagram( axes_object=axes_object, pod_by_threshold=ci_mean_dict[model_eval.POD_BY_THRESHOLD_KEY], success_ratio_by_threshold=ci_mean_dict[ model_eval.SR_BY_THRESHOLD_KEY], line_colour=line_colour, line_width=line_width, bias_line_colour=bias_line_colour, bias_line_width=bias_line_width) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.SR_BY_THRESHOLD_KEY], y_coords_bottom=ci_bottom_dict[model_eval.POD_BY_THRESHOLD_KEY], x_coords_top=ci_top_dict[model_eval.SR_BY_THRESHOLD_KEY], y_coords_top=ci_top_dict[model_eval.POD_BY_THRESHOLD_KEY], for_performance_diagram=True) polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(line_colour), TRANSPARENCY_FOR_CONFIDENCE_INTERVAL) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def plot_bootstrapped_roc_curve(axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, line_colour=DEFAULT_ROC_COLOUR, line_width=DEFAULT_ROC_WIDTH, random_line_colour=DEFAULT_RANDOM_ROC_COLOUR, random_line_width=DEFAULT_RANDOM_ROC_WIDTH): """Bootstrapped version of plot_roc_curve. T = number of probability thresholds in curve :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: Dictionary with the following keys, representing the bottom of the confidence interval. ci_bottom_dict['pod_by_threshold']: length-T numpy array of POD values (probability of detection). ci_bottom_dict['pofd_by_threshold']: length-T numpy array of POFD values (probability of false detection). :param ci_mean_dict: Same but for mean of confidence interval. :param ci_top_dict: Same but for top of confidence interval. :param line_colour: Colour for ROC curve (mean of confidence interval; in any format accepted by `matplotlib.colors`). The rest of the confidence interval will be shaded with the same colour but 50% opacity. :param line_width: Line width for ROC curve (mean of confidence interval). :param random_line_colour: Colour of reference line (ROC curve for a random predictor). :param random_line_width: Width of reference line. """ plot_roc_curve( axes_object=axes_object, pod_by_threshold=ci_mean_dict[model_eval.POD_BY_THRESHOLD_KEY], pofd_by_threshold=ci_mean_dict[model_eval.POFD_BY_THRESHOLD_KEY], line_colour=line_colour, line_width=line_width, random_line_colour=random_line_colour, random_line_width=random_line_width) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.POFD_BY_THRESHOLD_KEY], y_coords_bottom=ci_bottom_dict[model_eval.POD_BY_THRESHOLD_KEY], x_coords_top=ci_top_dict[model_eval.POFD_BY_THRESHOLD_KEY], y_coords_top=ci_top_dict[model_eval.POD_BY_THRESHOLD_KEY]) polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(line_colour), TRANSPARENCY_FOR_CONFIDENCE_INTERVAL) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def plot_bootstrapped_roc_curve(axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, line_colour=ROC_CURVE_COLOUR, plot_background=True): """Bootstrapped version of plot_roc_curve. T = number of probability thresholds in curve :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: Dictionary with the following keys, representing the bottom of the confidence interval. ci_bottom_dict['pod_by_threshold']: length-T numpy array of POD values (probability of detection). ci_bottom_dict['pofd_by_threshold']: length-T numpy array of POFD values (probability of false detection). :param ci_mean_dict: Same but for mean of confidence interval. :param ci_top_dict: Same but for top of confidence interval. :param line_colour: See doc for `plot_roc_curve`. :param plot_background: Same. :return: line_handle: Same. """ line_handle = plot_roc_curve( axes_object=axes_object, pod_by_threshold=ci_mean_dict[model_eval.POD_BY_THRESHOLD_KEY], pofd_by_threshold=ci_mean_dict[model_eval.POFD_BY_THRESHOLD_KEY], line_colour=line_colour, plot_background=plot_background) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.POFD_BY_THRESHOLD_KEY], y_coords_bottom=ci_bottom_dict[model_eval.POD_BY_THRESHOLD_KEY], x_coords_top=ci_top_dict[model_eval.POFD_BY_THRESHOLD_KEY], y_coords_top=ci_top_dict[model_eval.POD_BY_THRESHOLD_KEY]) if polygon_object is None: return line_handle polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(line_colour), POLYGON_OPACITY) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch) return line_handle
def plot_bootstrapped_reliability_curve(axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict): """Bootstrapped version of plot_reliability_curve. B = number of bins (separated by forecast probability) :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: Dictionary with the following keys, representing the bottom of the confidence interval. ci_bottom_dict['mean_forecast_by_bin']: length-B numpy array of mean forecast probabilities. ci_bottom_dict['event_frequency_by_bin']: length-B numpy array of conditional event frequencies. :param ci_mean_dict: Same but for mean of confidence interval. :param ci_top_dict: Same but for top of confidence interval. """ plot_reliability_curve( axes_object=axes_object, mean_forecast_by_bin=ci_mean_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], event_frequency_by_bin=ci_mean_dict[model_eval.EVENT_FREQ_BY_BIN_KEY]) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_bottom=ci_bottom_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], x_coords_top=ci_top_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_top=ci_top_dict[model_eval.EVENT_FREQ_BY_BIN_KEY]) if polygon_object is None: return polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(RELIABILITY_COLOUR), POLYGON_OPACITY) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def plot_bootstrapped_attributes_diagram(figure_object, axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, num_examples_by_bin): """Bootstrapped version of plot_attributes_diagram. :param figure_object: Instance of `matplotlib.figure.Figure`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: See doc for `plot_bootstrapped_reliability_curve`. :param ci_mean_dict: Same. :param ci_top_dict: Same. :param num_examples_by_bin: See doc for `plot_attributes_diagram`. """ plot_attributes_diagram( figure_object=figure_object, axes_object=axes_object, mean_forecast_by_bin=ci_mean_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], event_frequency_by_bin=ci_mean_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], num_examples_by_bin=num_examples_by_bin) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_bottom=ci_bottom_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], x_coords_top=ci_top_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_top=ci_top_dict[model_eval.EVENT_FREQ_BY_BIN_KEY]) if polygon_object is None: return polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(RELIABILITY_COLOUR), POLYGON_OPACITY) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def _label_bars(axes_object, y_coords, y_strings): """Labels bars in graph. J = number of bars :param axes_object: Will plot on these axes (instance of `matplotlib.axes._subplots.AxesSubplot`). :param y_coords: length-J numpy array with y-coordinates of bars. :param y_strings: length-J list of labels. """ x_min, x_max = pyplot.xlim() x_coord_for_text = x_min + 0.025 * (x_max - x_min) this_colour = plotting_utils.colour_from_numpy_to_tuple(TEXT_COLOUR) for j in range(len(y_coords)): axes_object.text(x_coord_for_text, y_coords[j], ' ' + y_strings[j], color=this_colour, horizontalalignment='left', verticalalignment='center', fontsize=LABEL_FONT_SIZE)
def plot_reliability_curve( axes_object, mean_forecast_by_bin, event_frequency_by_bin, line_colour=DEFAULT_RELIABILITY_COLOUR, line_width=DEFAULT_RELIABILITY_WIDTH, perfect_line_colour=DEFAULT_PERFECT_RELIABILITY_COLOUR, perfect_line_width=DEFAULT_PERFECT_RELIABILITY_WIDTH): """Plots reliability curve. B = number of bins (separated by forecast probability) :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param mean_forecast_by_bin: length-B numpy array of mean forecast probabilities. :param event_frequency_by_bin: length-B numpy array of mean observed labels (conditional event frequencies). :param line_colour: Colour (in any format accepted by `matplotlib.colors`). :param line_width: Line width (real positive number). :param perfect_line_colour: Colour of reference line (reliability curve with reliability = 0). :param perfect_line_width: Width of reference line. """ error_checking.assert_is_numpy_array(mean_forecast_by_bin, num_dimensions=1) error_checking.assert_is_geq_numpy_array(mean_forecast_by_bin, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(mean_forecast_by_bin, 1., allow_nan=True) num_bins = len(mean_forecast_by_bin) error_checking.assert_is_numpy_array(event_frequency_by_bin, exact_dimensions=numpy.array( [num_bins])) error_checking.assert_is_geq_numpy_array(event_frequency_by_bin, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(event_frequency_by_bin, 1., allow_nan=True) perfect_x_coords, perfect_y_coords = ( model_eval.get_perfect_reliability_curve()) axes_object.plot( perfect_x_coords, perfect_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(perfect_line_colour), linestyle='dashed', linewidth=perfect_line_width) nan_flags = numpy.logical_or(numpy.isnan(mean_forecast_by_bin), numpy.isnan(event_frequency_by_bin)) if not numpy.all(nan_flags): real_indices = numpy.where(numpy.invert(nan_flags))[0] axes_object.plot( mean_forecast_by_bin[real_indices], event_frequency_by_bin[real_indices], color=plotting_utils.colour_from_numpy_to_tuple(line_colour), linestyle='solid', linewidth=line_width) axes_object.set_xlabel('Forecast probability') axes_object.set_ylabel('Conditional event frequency') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.)
def plot_2d_grid_with_pm_signs(saliency_matrix_2d, axes_object, colour_map_object, max_absolute_colour_value, min_font_size=DEFAULT_MIN_FONT_SIZE, max_font_size=DEFAULT_MAX_FONT_SIZE): """Plots 2-D saliency map with plus and minus signs ("+" and "-"). M = number of rows in spatial grid N = number of columns in spatial grid :param saliency_matrix_2d: See doc for `plot_2d_grid_with_contours`. :param axes_object: Same. :param colour_map_object: Same. :param max_absolute_colour_value: Same. :param min_font_size: Minimum font size (used for zero saliency). :param max_font_size: Max font size (used for max absolute value). """ error_checking.assert_is_geq(max_absolute_colour_value, 0.) max_absolute_colour_value = max([max_absolute_colour_value, 0.001]) error_checking.assert_is_numpy_array_without_nan(saliency_matrix_2d) error_checking.assert_is_numpy_array(saliency_matrix_2d, num_dimensions=2) rgb_matrix, font_size_matrix = _saliency_to_colour_and_size( saliency_matrix=saliency_matrix_2d, colour_map_object=colour_map_object, max_absolute_colour_value=max_absolute_colour_value, min_font_size=min_font_size, max_font_size=max_font_size) num_grid_rows = saliency_matrix_2d.shape[0] num_grid_columns = saliency_matrix_2d.shape[1] x_coord_spacing = num_grid_columns**-1 y_coord_spacing = num_grid_rows**-1 x_coords, y_coords = grids.get_xy_grid_points( x_min_metres=x_coord_spacing / 2, y_min_metres=y_coord_spacing / 2, x_spacing_metres=x_coord_spacing, y_spacing_metres=y_coord_spacing, num_rows=num_grid_rows, num_columns=num_grid_columns) for i in range(num_grid_rows): for j in range(num_grid_columns): this_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( rgb_matrix[i, j, ...]) if saliency_matrix_2d[i, j] >= 0: axes_object.text(x_coords[i], y_coords[j], '+', fontsize=font_size_matrix[i, j], color=this_colour_tuple, horizontalalignment='center', verticalalignment='center', transform=axes_object.transAxes) else: axes_object.text(x_coords[i], y_coords[j], '_', fontsize=font_size_matrix[i, j], color=this_colour_tuple, horizontalalignment='center', verticalalignment='bottom', transform=axes_object.transAxes)
def plot_performance_diagram(axes_object, pod_by_threshold, success_ratio_by_threshold, line_colour=DEFAULT_PERFORMANCE_COLOUR, line_width=DEFAULT_PERFORMANCE_WIDTH, bias_line_colour=DEFAULT_FREQ_BIAS_COLOUR, bias_line_width=DEFAULT_FREQ_BIAS_WIDTH): """Plots performance diagram. T = number of binarization thresholds For the definition of a "binarization threshold" and the role they play in performance diagrams, see `model_evaluation.get_points_in_performance_diagram`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param pod_by_threshold: length-T numpy array of POD (probability of detection) values. :param success_ratio_by_threshold: length-T numpy array of success ratios. :param line_colour: Colour (in any format accepted by `matplotlib.colors`). :param line_width: Line width (real positive number). :param bias_line_colour: Colour of contour lines for frequency bias. :param bias_line_width: Width of contour lines for frequency bias. """ error_checking.assert_is_numpy_array(pod_by_threshold, num_dimensions=1) error_checking.assert_is_geq_numpy_array(pod_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pod_by_threshold, 1., allow_nan=True) num_thresholds = len(pod_by_threshold) error_checking.assert_is_numpy_array(success_ratio_by_threshold, exact_dimensions=numpy.array( [num_thresholds])) error_checking.assert_is_geq_numpy_array(success_ratio_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(success_ratio_by_threshold, 1., allow_nan=True) success_ratio_matrix, pod_matrix = model_eval.get_sr_pod_grid() csi_matrix = model_eval.csi_from_sr_and_pod(success_ratio_matrix, pod_matrix) frequency_bias_matrix = model_eval.frequency_bias_from_sr_and_pod( success_ratio_matrix, pod_matrix) this_colour_map_object, this_colour_norm_object = _get_csi_colour_scheme() pyplot.contourf(success_ratio_matrix, pod_matrix, csi_matrix, LEVELS_FOR_CSI_CONTOURS, cmap=this_colour_map_object, norm=this_colour_norm_object, vmin=0., vmax=1., axes=axes_object) colour_bar_object = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_object, data_matrix=csi_matrix, colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='vertical', extend_min=False, extend_max=False) colour_bar_object.set_label('CSI (critical success index)') bias_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( bias_line_colour) bias_colours_2d_tuple = () for _ in range(len(LEVELS_FOR_FREQ_BIAS_CONTOURS)): bias_colours_2d_tuple += (bias_colour_tuple, ) bias_contour_object = pyplot.contour(success_ratio_matrix, pod_matrix, frequency_bias_matrix, LEVELS_FOR_FREQ_BIAS_CONTOURS, colors=bias_colours_2d_tuple, linewidths=bias_line_width, linestyles='dashed', axes=axes_object) pyplot.clabel(bias_contour_object, inline=True, inline_spacing=PIXEL_PADDING_FOR_FREQ_BIAS_LABELS, fmt=STRING_FORMAT_FOR_FREQ_BIAS_LABELS, fontsize=FONT_SIZE) nan_flags = numpy.logical_or(numpy.isnan(success_ratio_by_threshold), numpy.isnan(pod_by_threshold)) if not numpy.all(nan_flags): real_indices = numpy.where(numpy.invert(nan_flags))[0] axes_object.plot( success_ratio_by_threshold[real_indices], pod_by_threshold[real_indices], color=plotting_utils.colour_from_numpy_to_tuple(line_colour), linestyle='solid', linewidth=line_width) axes_object.set_xlabel('Success ratio (1 - FAR)') axes_object.set_ylabel('POD (probability of detection)') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.)
def plot_reliability_curve(axes_object, mean_forecast_by_bin, event_frequency_by_bin): """Plots reliability curve. B = number of bins (separated by forecast probability) :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param mean_forecast_by_bin: length-B numpy array of mean forecast probabilities. :param event_frequency_by_bin: length-B numpy array of mean observed labels (conditional event frequencies). """ error_checking.assert_is_numpy_array(mean_forecast_by_bin, num_dimensions=1) error_checking.assert_is_geq_numpy_array(mean_forecast_by_bin, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(mean_forecast_by_bin, 1., allow_nan=True) num_bins = len(mean_forecast_by_bin) expected_dim = numpy.array([num_bins], dtype=int) error_checking.assert_is_numpy_array(event_frequency_by_bin, exact_dimensions=expected_dim) error_checking.assert_is_geq_numpy_array(event_frequency_by_bin, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(event_frequency_by_bin, 1., allow_nan=True) perfect_x_coords, perfect_y_coords = ( model_eval.get_perfect_reliability_curve()) axes_object.plot( perfect_x_coords, perfect_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(PERFECT_RELIA_COLOUR), linestyle='dashed', linewidth=PERFECT_RELIA_WIDTH) nan_flags = numpy.logical_or(numpy.isnan(mean_forecast_by_bin), numpy.isnan(event_frequency_by_bin)) if not numpy.all(nan_flags): real_indices = numpy.where(numpy.invert(nan_flags))[0] axes_object.plot(mean_forecast_by_bin[real_indices], event_frequency_by_bin[real_indices], color=plotting_utils.colour_from_numpy_to_tuple( RELIABILITY_COLOUR), linestyle='solid', linewidth=RELIABILITY_WIDTH) axes_object.set_xlabel('Forecast probability') axes_object.set_ylabel('Conditional event frequency') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.)
def plot_roc_curve(axes_object, pod_by_threshold, pofd_by_threshold, line_colour=DEFAULT_ROC_COLOUR, line_width=DEFAULT_ROC_WIDTH, random_line_colour=DEFAULT_RANDOM_ROC_COLOUR, random_line_width=DEFAULT_RANDOM_ROC_WIDTH): """Plots ROC (receiver operating characteristic) curve. T = number of binarization thresholds For the definition of a "binarization threshold" and the role they play in ROC curves, see `model_evaluation.get_points_in_roc_curve`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param pod_by_threshold: length-T numpy array of POD (probability of detection) values. :param pofd_by_threshold: length-T numpy array of POFD (probability of false detection) values. :param line_colour: Colour (in any format accepted by `matplotlib.colors`). :param line_width: Line width (real positive number). :param random_line_colour: Colour of reference line (ROC curve for a random predictor). :param random_line_width: Width of reference line. """ error_checking.assert_is_numpy_array(pod_by_threshold, num_dimensions=1) error_checking.assert_is_geq_numpy_array(pod_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pod_by_threshold, 1., allow_nan=True) num_thresholds = len(pod_by_threshold) error_checking.assert_is_numpy_array(pofd_by_threshold, exact_dimensions=numpy.array( [num_thresholds])) error_checking.assert_is_geq_numpy_array(pofd_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pofd_by_threshold, 1., allow_nan=True) pofd_matrix, pod_matrix = model_eval.get_pofd_pod_grid() peirce_score_matrix = pod_matrix - pofd_matrix this_colour_map_object, this_colour_norm_object = _get_peirce_colour_scheme( ) pyplot.contourf(pofd_matrix, pod_matrix, peirce_score_matrix, LEVELS_FOR_CSI_CONTOURS, cmap=this_colour_map_object, norm=this_colour_norm_object, vmin=0., vmax=1., axes=axes_object) colour_bar_object = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_object, data_matrix=peirce_score_matrix, colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='vertical', extend_min=False, extend_max=False) colour_bar_object.set_label('Peirce score (POD minus POFD)') random_x_coords, random_y_coords = model_eval.get_random_roc_curve() axes_object.plot( random_x_coords, random_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(random_line_colour), linestyle='dashed', linewidth=random_line_width) nan_flags = numpy.logical_or(numpy.isnan(pofd_by_threshold), numpy.isnan(pod_by_threshold)) if not numpy.all(nan_flags): real_indices = numpy.where(numpy.invert(nan_flags))[0] axes_object.plot( pofd_by_threshold[real_indices], pod_by_threshold[real_indices], color=plotting_utils.colour_from_numpy_to_tuple(line_colour), linestyle='solid', linewidth=line_width) axes_object.set_xlabel('POFD (probability of false detection)') axes_object.set_ylabel('POD (probability of detection)') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.)
def plot_bootstrapped_attributes_diagram( figure_object, axes_object, ci_bottom_dict, ci_mean_dict, ci_top_dict, num_examples_by_bin, reliability_line_colour=DEFAULT_RELIABILITY_COLOUR, reliability_line_width=DEFAULT_RELIABILITY_WIDTH, perfect_relia_line_colour=DEFAULT_PERFECT_RELIABILITY_COLOUR, perfect_relia_line_width=DEFAULT_PERFECT_RELIABILITY_WIDTH, no_skill_line_colour=DEFAULT_ZERO_BSS_COLOUR, no_skill_line_width=DEFAULT_ZERO_BSS_WIDTH, other_line_colour=DEFAULT_CLIMATOLOGY_COLOUR, other_line_width=DEFAULT_CLIMATOLOGY_WIDTH, histogram_bar_face_colour=DEFAULT_HISTOGRAM_FACE_COLOUR, histogram_bar_edge_colour=DEFAULT_HISTOGRAM_EDGE_COLOUR, histogram_bar_edge_width=DEFAULT_HISTOGRAM_EDGE_WIDTH): """Bootstrapped version of plot_attributes_diagram. :param figure_object: Instance of `matplotlib.figure.Figure`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param ci_bottom_dict: See doc for `plot_bootstrapped_reliability_curve`. :param ci_mean_dict: Same. :param ci_top_dict: Same. :param num_examples_by_bin: See doc for `plot_attributes_diagram`. :param reliability_line_colour: Same. :param reliability_line_width: Same. :param perfect_relia_line_colour: Same. :param perfect_relia_line_width: Same. :param no_skill_line_colour: Same. :param no_skill_line_width: Same. :param other_line_colour: Same. :param other_line_width: Same. :param histogram_bar_face_colour: Same. :param histogram_bar_edge_colour: Same. :param histogram_bar_edge_width: Same. """ plot_attributes_diagram( figure_object=figure_object, axes_object=axes_object, mean_forecast_by_bin=ci_mean_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], event_frequency_by_bin=ci_mean_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], num_examples_by_bin=num_examples_by_bin, reliability_line_colour=reliability_line_colour, reliability_line_width=reliability_line_width, perfect_relia_line_colour=perfect_relia_line_colour, perfect_relia_line_width=perfect_relia_line_width, no_skill_line_colour=no_skill_line_colour, no_skill_line_width=no_skill_line_width, other_line_colour=other_line_colour, other_line_width=other_line_width, histogram_bar_face_colour=histogram_bar_face_colour, histogram_bar_edge_colour=histogram_bar_edge_colour, histogram_bar_edge_width=histogram_bar_edge_width) polygon_object = _confidence_interval_to_polygon( x_coords_bottom=ci_bottom_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_bottom=ci_bottom_dict[model_eval.EVENT_FREQ_BY_BIN_KEY], x_coords_top=ci_top_dict[model_eval.MEAN_FORECAST_BY_BIN_KEY], y_coords_top=ci_top_dict[model_eval.EVENT_FREQ_BY_BIN_KEY]) polygon_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(reliability_line_colour), TRANSPARENCY_FOR_CONFIDENCE_INTERVAL) polygon_patch = PolygonPatch(polygon_object, lw=0, ec=polygon_colour, fc=polygon_colour) axes_object.add_patch(polygon_patch)
def _plot_background_of_attributes_diagram(axes_object, climatology): """Plots background (references lines and polygons) of attributes diagram. For more on the attributes diagram, see Hsu and Murphy (1986). BSS = Brier skill score. For more on the BSS, see `model_evaluation.get_brier_skill_score`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param climatology: Event frequency for the entire dataset. """ error_checking.assert_is_geq(climatology, 0.) error_checking.assert_is_leq(climatology, 1.) (x_coords_left_skill_area, y_coords_left_skill_area, x_coords_right_skill_area, y_coords_right_skill_area ) = model_eval.get_skill_areas_in_reliability_curve(climatology) skill_area_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(ZERO_BSS_COLOUR), POSITIVE_BSS_OPACITY) left_polygon_object = polygons.vertex_arrays_to_polygon_object( x_coords_left_skill_area, y_coords_left_skill_area) left_polygon_patch = PolygonPatch(left_polygon_object, lw=0, ec=skill_area_colour, fc=skill_area_colour) axes_object.add_patch(left_polygon_patch) right_polygon_object = polygons.vertex_arrays_to_polygon_object( x_coords_right_skill_area, y_coords_right_skill_area) right_polygon_patch = PolygonPatch(right_polygon_object, lw=0, ec=skill_area_colour, fc=skill_area_colour) axes_object.add_patch(right_polygon_patch) no_skill_x_coords, no_skill_y_coords = ( model_eval.get_no_skill_reliability_curve(climatology)) axes_object.plot( no_skill_x_coords, no_skill_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(ZERO_BSS_COLOUR), linestyle='solid', linewidth=ZERO_BSS_LINE_WIDTH) climo_x_coords, climo_y_coords = ( model_eval.get_climatology_line_for_reliability_curve(climatology)) axes_object.plot( climo_x_coords, climo_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(CLIMO_COLOUR), linestyle='dashed', linewidth=CLIMO_LINE_WIDTH) no_resolution_x_coords, no_resolution_y_coords = ( model_eval.get_no_resolution_line_for_reliability_curve(climatology)) axes_object.plot( no_resolution_x_coords, no_resolution_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(CLIMO_COLOUR), linestyle='dashed', linewidth=CLIMO_LINE_WIDTH)
def _plot_background_of_attributes_diagram( axes_object, climatology, no_skill_line_colour=DEFAULT_ZERO_BSS_COLOUR, no_skill_line_width=DEFAULT_ZERO_BSS_WIDTH, other_line_colour=DEFAULT_CLIMATOLOGY_COLOUR, other_line_width=DEFAULT_CLIMATOLOGY_WIDTH): """Plots background (references lines and polygons) of attributes diagram. For more on the attributes diagram, see Hsu and Murphy (1986). BSS = Brier skill score. For more on the BSS, see `model_evaluation.get_brier_skill_score`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param climatology: Event frequency for the entire dataset. :param no_skill_line_colour: Colour (in any format accepted by `matplotlib.colors`) of no-skill line, where BSS = 0. :param no_skill_line_width: Width (real positive number) of no-skill line. :param other_line_colour: Colour of climatology and no-resolution lines. :param other_line_width: Width of climatology and no-resolution lines. """ error_checking.assert_is_geq(climatology, 0.) error_checking.assert_is_leq(climatology, 1.) (x_vertices_for_left_skill_area, y_vertices_for_left_skill_area, x_vertices_for_right_skill_area, y_vertices_for_right_skill_area ) = model_eval.get_skill_areas_in_reliability_curve(climatology) skill_area_colour = matplotlib.colors.to_rgba( plotting_utils.colour_from_numpy_to_tuple(no_skill_line_colour), TRANSPARENCY_FOR_POSITIVE_BSS_AREA) left_polygon_object = polygons.vertex_arrays_to_polygon_object( x_vertices_for_left_skill_area, y_vertices_for_left_skill_area) left_polygon_patch = PolygonPatch(left_polygon_object, lw=0, ec=skill_area_colour, fc=skill_area_colour) axes_object.add_patch(left_polygon_patch) right_polygon_object = polygons.vertex_arrays_to_polygon_object( x_vertices_for_right_skill_area, y_vertices_for_right_skill_area) right_polygon_patch = PolygonPatch(right_polygon_object, lw=0, ec=skill_area_colour, fc=skill_area_colour) axes_object.add_patch(right_polygon_patch) no_skill_x_coords, no_skill_y_coords = ( model_eval.get_no_skill_reliability_curve(climatology)) axes_object.plot( no_skill_x_coords, no_skill_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(no_skill_line_colour), linestyle='solid', linewidth=no_skill_line_width) climo_x_coords, climo_y_coords = ( model_eval.get_climatology_line_for_reliability_curve(climatology)) axes_object.plot( climo_x_coords, climo_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(other_line_colour), linestyle='dashed', linewidth=other_line_width) no_resolution_x_coords, no_resolution_y_coords = ( model_eval.get_no_resolution_line_for_reliability_curve(climatology)) axes_object.plot( no_resolution_x_coords, no_resolution_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(other_line_colour), linestyle='dashed', linewidth=other_line_width)
def plot_performance_diagram(axes_object, pod_by_threshold, success_ratio_by_threshold, line_colour=PERF_DIAGRAM_COLOUR, plot_background=True): """Plots performance diagram. T = number of binarization thresholds For the definition of a "binarization threshold" and the role they play in performance diagrams, see `model_evaluation.get_points_in_performance_diagram`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param pod_by_threshold: length-T numpy array of POD (probability of detection) values. :param success_ratio_by_threshold: length-T numpy array of success ratios. :param line_colour: Line colour. :param plot_background: Boolean flag. If True, will plot background (frequency-bias and CSI contours). :return: line_handle: Line handle for ROC curve. """ error_checking.assert_is_numpy_array(pod_by_threshold, num_dimensions=1) error_checking.assert_is_geq_numpy_array(pod_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pod_by_threshold, 1., allow_nan=True) num_thresholds = len(pod_by_threshold) expected_dim = numpy.array([num_thresholds], dtype=int) error_checking.assert_is_numpy_array(success_ratio_by_threshold, exact_dimensions=expected_dim) error_checking.assert_is_geq_numpy_array(success_ratio_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(success_ratio_by_threshold, 1., allow_nan=True) error_checking.assert_is_boolean(plot_background) if plot_background: success_ratio_matrix, pod_matrix = model_eval.get_sr_pod_grid() csi_matrix = model_eval.csi_from_sr_and_pod( success_ratio_array=success_ratio_matrix, pod_array=pod_matrix) frequency_bias_matrix = model_eval.frequency_bias_from_sr_and_pod( success_ratio_array=success_ratio_matrix, pod_array=pod_matrix) this_colour_map_object, this_colour_norm_object = ( _get_csi_colour_scheme()) pyplot.contourf(success_ratio_matrix, pod_matrix, csi_matrix, CSI_LEVELS, cmap=this_colour_map_object, norm=this_colour_norm_object, vmin=0., vmax=1., axes=axes_object) colour_bar_object = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_object, data_matrix=csi_matrix, colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='vertical', extend_min=False, extend_max=False, fraction_of_axis_length=0.8) colour_bar_object.set_label('CSI (critical success index)') bias_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( FREQ_BIAS_COLOUR) bias_colours_2d_tuple = () for _ in range(len(FREQ_BIAS_LEVELS)): bias_colours_2d_tuple += (bias_colour_tuple, ) bias_contour_object = pyplot.contour(success_ratio_matrix, pod_matrix, frequency_bias_matrix, FREQ_BIAS_LEVELS, colors=bias_colours_2d_tuple, linewidths=FREQ_BIAS_WIDTH, linestyles='dashed', axes=axes_object) pyplot.clabel(bias_contour_object, inline=True, inline_spacing=FREQ_BIAS_PADDING, fmt=FREQ_BIAS_STRING_FORMAT, fontsize=FONT_SIZE) nan_flags = numpy.logical_or(numpy.isnan(success_ratio_by_threshold), numpy.isnan(pod_by_threshold)) if numpy.all(nan_flags): line_handle = None else: real_indices = numpy.where(numpy.invert(nan_flags))[0] line_handle = axes_object.plot( success_ratio_by_threshold[real_indices], pod_by_threshold[real_indices], color=plotting_utils.colour_from_numpy_to_tuple(line_colour), linestyle='solid', linewidth=PERF_DIAGRAM_WIDTH)[0] axes_object.set_xlabel('Success ratio (1 - FAR)') axes_object.set_ylabel('POD (probability of detection)') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.) return line_handle
def plot_storm_ids( storm_object_table, axes_object, basemap_object, plot_near_centroids=False, include_secondary_ids=False, font_colour=DEFAULT_FONT_COLOUR, font_size=DEFAULT_FONT_SIZE): """Plots storm IDs as text. :param storm_object_table: See doc for `plot_storm_outlines`. :param axes_object: Same. :param basemap_object: Same. :param plot_near_centroids: Boolean flag. If True, will plot each ID near the storm centroid. If False, will plot each ID near southeasternmost point in storm outline. :param include_secondary_ids: Boolean flag. If True, will plot full IDs (primary_secondary). If False, will plot only primary IDs. :param font_colour: Font colour. :param font_size: Font size. """ error_checking.assert_is_boolean(plot_near_centroids) error_checking.assert_is_boolean(include_secondary_ids) font_colour_tuple = plotting_utils.colour_from_numpy_to_tuple(font_colour) num_storm_objects = len(storm_object_table.index) if plot_near_centroids: text_x_coords_metres, text_y_coords_metres = basemap_object( storm_object_table[tracking_utils.CENTROID_LONGITUDE_COLUMN].values, storm_object_table[tracking_utils.CENTROID_LATITUDE_COLUMN].values ) else: text_x_coords_metres = numpy.full(num_storm_objects, numpy.nan) text_y_coords_metres = numpy.full(num_storm_objects, numpy.nan) for i in range(num_storm_objects): this_vertex_dict_latlng = polygons.polygon_object_to_vertex_arrays( storm_object_table[ tracking_utils.LATLNG_POLYGON_COLUMN].values[i] ) these_x_metres, these_y_metres = basemap_object( this_vertex_dict_latlng[polygons.EXTERIOR_X_COLUMN], this_vertex_dict_latlng[polygons.EXTERIOR_Y_COLUMN] ) this_index = numpy.argmax(these_x_metres - these_y_metres) text_x_coords_metres[i] = these_x_metres[this_index] text_y_coords_metres[i] = these_y_metres[this_index] for i in range(num_storm_objects): this_primary_id_string = storm_object_table[ tracking_utils.PRIMARY_ID_COLUMN].values[i] try: this_primary_id_string = this_primary_id_string[-4:] except ValueError: pass if include_secondary_ids: this_secondary_id_string = storm_object_table[ tracking_utils.SECONDARY_ID_COLUMN].values[i] try: this_secondary_id_string = this_secondary_id_string[-4:] except ValueError: pass this_label_string = '{0:s}_{1:s}'.format( this_primary_id_string, this_secondary_id_string) else: this_label_string = this_primary_id_string axes_object.text( text_x_coords_metres[i], text_y_coords_metres[i], this_label_string, fontsize=font_size, fontweight='bold', color=font_colour_tuple, horizontalalignment='left', verticalalignment='top')
def plot_roc_curve(axes_object, pod_by_threshold, pofd_by_threshold, line_colour=ROC_CURVE_COLOUR, plot_background=True): """Plots ROC (receiver operating characteristic) curve. T = number of binarization thresholds For the definition of a "binarization threshold" and the role they play in ROC curves, see `model_evaluation.get_points_in_roc_curve`. :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`. :param pod_by_threshold: length-T numpy array of POD (probability of detection) values. :param pofd_by_threshold: length-T numpy array of POFD (probability of false detection) values. :param line_colour: Line colour. :param plot_background: Boolean flag. If True, will plot background (reference line and Peirce-score contours). :return: line_handle: Line handle for ROC curve. """ error_checking.assert_is_numpy_array(pod_by_threshold, num_dimensions=1) error_checking.assert_is_geq_numpy_array(pod_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pod_by_threshold, 1., allow_nan=True) num_thresholds = len(pod_by_threshold) expected_dim = numpy.array([num_thresholds], dtype=int) error_checking.assert_is_numpy_array(pofd_by_threshold, exact_dimensions=expected_dim) error_checking.assert_is_geq_numpy_array(pofd_by_threshold, 0., allow_nan=True) error_checking.assert_is_leq_numpy_array(pofd_by_threshold, 1., allow_nan=True) error_checking.assert_is_boolean(plot_background) if plot_background: pofd_matrix, pod_matrix = model_eval.get_pofd_pod_grid() peirce_score_matrix = pod_matrix - pofd_matrix this_colour_map_object, this_colour_norm_object = ( _get_peirce_colour_scheme()) pyplot.contourf(pofd_matrix, pod_matrix, peirce_score_matrix, CSI_LEVELS, cmap=this_colour_map_object, norm=this_colour_norm_object, vmin=0., vmax=1., axes=axes_object) colour_bar_object = plotting_utils.plot_colour_bar( axes_object_or_matrix=axes_object, data_matrix=peirce_score_matrix, colour_map_object=this_colour_map_object, colour_norm_object=this_colour_norm_object, orientation_string='vertical', extend_min=False, extend_max=False, fraction_of_axis_length=0.8) colour_bar_object.set_label('Peirce score (POD minus POFD)') random_x_coords, random_y_coords = model_eval.get_random_roc_curve() axes_object.plot( random_x_coords, random_y_coords, color=plotting_utils.colour_from_numpy_to_tuple(RANDOM_ROC_COLOUR), linestyle='dashed', linewidth=RANDOM_ROC_WIDTH) nan_flags = numpy.logical_or(numpy.isnan(pofd_by_threshold), numpy.isnan(pod_by_threshold)) if numpy.all(nan_flags): line_handle = None else: real_indices = numpy.where(numpy.invert(nan_flags))[0] line_handle = axes_object.plot( pofd_by_threshold[real_indices], pod_by_threshold[real_indices], color=plotting_utils.colour_from_numpy_to_tuple(line_colour), linestyle='solid', linewidth=ROC_CURVE_WIDTH)[0] axes_object.set_xlabel('POFD (probability of false detection)') axes_object.set_ylabel('POD (probability of detection)') axes_object.set_xlim(0., 1.) axes_object.set_ylim(0., 1.) return line_handle
def _plot_2d_regions(figure_objects, axes_object_matrices, model_metadata_dict, list_of_polygon_objects, output_dir_name, full_storm_id_string=None, storm_time_unix_sec=None): """Plots regions of interest for 2-D radar data. :param figure_objects: See doc for `_plot_3d_radar_cam`. :param axes_object_matrices: Same. :param model_metadata_dict: Same. :param list_of_polygon_objects: List of polygons (instances of `shapely.geometry.Polygon`), demarcating regions of interest. :param output_dir_name: See doc for `_plot_3d_radar_cam`. :param full_storm_id_string: Same. :param storm_time_unix_sec: Same. """ conv_2d3d = model_metadata_dict[cnn.CONV_2D3D_KEY] figure_index = 1 if conv_2d3d else 0 training_option_dict = model_metadata_dict[cnn.TRAINING_OPTION_DICT_KEY] num_grid_rows = training_option_dict[trainval_io.NUM_ROWS_KEY] num_grid_rows *= 1 + int(conv_2d3d) list_of_layer_operation_dicts = model_metadata_dict[ cnn.LAYER_OPERATIONS_KEY] if list_of_layer_operation_dicts is None: num_channels = len(training_option_dict[trainval_io.RADAR_FIELDS_KEY]) else: num_channels = len(list_of_layer_operation_dicts) for this_polygon_object in list_of_polygon_objects: for k in range(num_channels): i, j = numpy.unravel_index( k, axes_object_matrices[figure_index].shape, order='F') these_grid_columns = numpy.array( this_polygon_object.exterior.xy[0]) these_grid_rows = num_grid_rows - numpy.array( this_polygon_object.exterior.xy[1]) axes_object_matrices[figure_index][i, j].plot( these_grid_columns, these_grid_rows, color=plotting_utils.colour_from_numpy_to_tuple(REGION_COLOUR), linestyle='solid', linewidth=REGION_LINE_WIDTH) pmm_flag = full_storm_id_string is None and storm_time_unix_sec is None output_file_name = plot_input_examples.metadata_to_file_name( output_dir_name=output_dir_name, is_sounding=False, pmm_flag=pmm_flag, full_storm_id_string=full_storm_id_string, storm_time_unix_sec=storm_time_unix_sec, radar_field_name='shear' if conv_2d3d else None) print('Saving figure to: "{0:s}"...'.format(output_file_name)) figure_objects[figure_index].savefig(output_file_name, dpi=FIGURE_RESOLUTION_DPI, pad_inches=0, bbox_inches='tight') pyplot.close(figure_objects[figure_index])
def plot_saliency_for_sounding(saliency_matrix, sounding_field_names, pressure_levels_mb, colour_map_object, max_absolute_colour_value, min_font_size=DEFAULT_MIN_SOUNDING_FONT_SIZE, max_font_size=DEFAULT_MAX_SOUNDING_FONT_SIZE): """Plots saliency for one sounding. P = number of pressure levels F = number of fields :param saliency_matrix: P-by-F numpy array of saliency values. :param sounding_field_names: length-F list of field names. :param pressure_levels_mb: length-P list of pressure levels (millibars). :param colour_map_object: See doc for `plot_2d_grid`. :param max_absolute_colour_value: Same. :param min_font_size: Same. :param max_font_size: Same. """ error_checking.assert_is_geq(max_absolute_colour_value, 0.) max_absolute_colour_value = max([max_absolute_colour_value, 0.001]) error_checking.assert_is_greater_numpy_array(pressure_levels_mb, 0.) error_checking.assert_is_numpy_array(pressure_levels_mb, num_dimensions=1) error_checking.assert_is_list(sounding_field_names) error_checking.assert_is_numpy_array(numpy.array(sounding_field_names), num_dimensions=1) num_pressure_levels = len(pressure_levels_mb) num_sounding_fields = len(sounding_field_names) error_checking.assert_is_numpy_array_without_nan(saliency_matrix) error_checking.assert_is_numpy_array(saliency_matrix, exact_dimensions=numpy.array([ num_pressure_levels, num_sounding_fields ])) try: u_wind_index = sounding_field_names.index(soundings.U_WIND_NAME) v_wind_index = sounding_field_names.index(soundings.V_WIND_NAME) plot_wind_barbs = True except ValueError: plot_wind_barbs = False if plot_wind_barbs: u_wind_saliency_values = saliency_matrix[:, u_wind_index] v_wind_saliency_values = saliency_matrix[:, v_wind_index] wind_saliency_magnitudes = numpy.sqrt(u_wind_saliency_values**2 + v_wind_saliency_values**2) colour_norm_object = pyplot.Normalize(vmin=0., vmax=max_absolute_colour_value) rgb_matrix_for_wind = colour_map_object( colour_norm_object(wind_saliency_magnitudes))[..., :-1] non_wind_flags = numpy.array( [f not in WIND_COMPONENT_NAMES for f in sounding_field_names], dtype=bool) non_wind_indices = numpy.where(non_wind_flags)[0] saliency_matrix = saliency_matrix[:, non_wind_indices] sounding_field_names = [ sounding_field_names[k] for k in non_wind_indices ] sounding_field_names.append(WIND_NAME) num_sounding_fields = len(sounding_field_names) rgb_matrix, font_size_matrix = _saliency_to_colour_and_size( saliency_matrix=saliency_matrix, colour_map_object=colour_map_object, max_absolute_colour_value=max_absolute_colour_value, min_font_size=min_font_size, max_font_size=max_font_size) _, axes_object = pyplot.subplots(1, 1, figsize=(FIGURE_WIDTH_INCHES, FIGURE_HEIGHT_INCHES)) axes_object.set_facecolor( plotting_utils.colour_from_numpy_to_tuple( SOUNDING_SALIENCY_BACKGROUND_COLOUR)) for k in range(num_sounding_fields): if sounding_field_names[k] == WIND_NAME: for j in range(num_pressure_levels): this_vector = numpy.array( [u_wind_saliency_values[j], v_wind_saliency_values[j]]) this_vector = (WIND_SALIENCY_MULTIPLIER * this_vector / numpy.linalg.norm(this_vector, ord=2)) this_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( rgb_matrix_for_wind[j, ...]) axes_object.barbs(k, pressure_levels_mb[j], this_vector[0], this_vector[1], length=WIND_BARB_LENGTH, fill_empty=True, rounding=False, sizes={'emptybarb': EMPTY_WIND_BARB_RADIUS}, color=this_colour_tuple) continue for j in range(num_pressure_levels): this_colour_tuple = plotting_utils.colour_from_numpy_to_tuple( rgb_matrix[j, k, ...]) if saliency_matrix[j, k] >= 0: axes_object.text(k, pressure_levels_mb[j], '+', fontsize=font_size_matrix[j, k], color=this_colour_tuple, horizontalalignment='center', verticalalignment='center') else: axes_object.text(k, pressure_levels_mb[j], '_', fontsize=font_size_matrix[j, k], color=this_colour_tuple, horizontalalignment='center', verticalalignment='bottom') axes_object.set_xlim(-0.5, num_sounding_fields - 0.5) axes_object.set_ylim(100, 1000) axes_object.invert_yaxis() pyplot.yscale('log') pyplot.minorticks_off() y_tick_locations = numpy.linspace(100, 1000, num=10, dtype=int) y_tick_labels = ['{0:d}'.format(p) for p in y_tick_locations] pyplot.yticks(y_tick_locations, y_tick_labels) x_tick_locations = numpy.linspace(0, num_sounding_fields - 1, num=num_sounding_fields, dtype=float) x_tick_labels = [FIELD_NAME_TO_LATEX_DICT[f] for f in sounding_field_names] pyplot.xticks(x_tick_locations, x_tick_labels) colour_bar_object = plotting_utils.plot_linear_colour_bar( axes_object_or_matrix=axes_object, data_matrix=saliency_matrix, colour_map_object=colour_map_object, min_value=0., max_value=max_absolute_colour_value, orientation_string='vertical', extend_min=True, extend_max=True) colour_bar_object.set_label('Saliency (absolute value)')
def plot_storm_centroids( storm_object_table, axes_object, basemap_object, colour_map_object='random', colour_min_unix_sec=None, colour_max_unix_sec=None, constant_colour=DEFAULT_CENTROID_COLOUR, marker_type=DEFAULT_CENTROID_MARKER_TYPE, marker_size=DEFAULT_CENTROID_MARKER_SIZE): """Plots storm centroids. :param storm_object_table: See doc for `plot_storm_tracks`. :param axes_object: Same. :param basemap_object: Same. :param colour_map_object: See doc for `_process_colour_args`. :param colour_min_unix_sec: Same. :param colour_max_unix_sec: Same. :param constant_colour: Same. :param marker_type: Marker type. :param marker_size: Marker size. :return: colour_bar_object: Handle for colour bar. If `colour_map_object is None`, this will also be None. """ x_coords_metres, y_coords_metres = basemap_object( storm_object_table[tracking_utils.CENTROID_LONGITUDE_COLUMN].values, storm_object_table[tracking_utils.CENTROID_LATITUDE_COLUMN].values ) storm_object_table = storm_object_table.assign(**{ tracking_utils.CENTROID_X_COLUMN: x_coords_metres, tracking_utils.CENTROID_Y_COLUMN: y_coords_metres }) rgb_matrix, colour_map_object, colour_norm_object = _process_colour_args( colour_map_object=colour_map_object, colour_min_unix_sec=colour_min_unix_sec, colour_max_unix_sec=colour_max_unix_sec, constant_colour=constant_colour, storm_object_table=storm_object_table ) num_colours = None if rgb_matrix is None else rgb_matrix.shape[0] track_primary_id_strings, object_to_track_indices = numpy.unique( storm_object_table[tracking_utils.PRIMARY_ID_COLUMN].values, return_inverse=True ) num_tracks = len(track_primary_id_strings) for j in range(num_tracks): these_object_indices = numpy.where(object_to_track_indices == j)[0] if colour_map_object is None: this_colour = rgb_matrix[numpy.mod(j, num_colours), :] this_colour = plotting_utils.colour_from_numpy_to_tuple(this_colour) axes_object.plot( x_coords_metres[these_object_indices], y_coords_metres[these_object_indices], linestyle='None', marker=marker_type, markersize=marker_size, markeredgewidth=0, markerfacecolor=this_colour, markeredgecolor=this_colour ) continue for i in these_object_indices: this_colour = colour_map_object(colour_norm_object( storm_object_table[tracking_utils.VALID_TIME_COLUMN].values[i] )) this_colour = plotting_utils.colour_from_numpy_to_tuple(this_colour) axes_object.plot( x_coords_metres[i], y_coords_metres[i], linestyle='None', marker=marker_type, markersize=marker_size, markeredgewidth=0, markerfacecolor=this_colour, markeredgecolor=this_colour ) if colour_map_object is None: return None return _add_colour_bar( axes_object=axes_object, basemap_object=basemap_object, colour_map_object=colour_map_object, colour_norm_object=colour_norm_object)
def _plot_tornadoes(tornado_table, colour_map_object, colour_norm_object, genesis_only, axes_object, basemap_object): """Plots start/end point of each tornado. :param tornado_table: pandas DataFrame returned by `linkage.read_linkage_file`. :param colour_map_object: Colour map (instance of `matplotlib.pyplot.cm`). Tornado markers will be coloured by time. :param colour_norm_object: Colour-normalizer (instance of `matplotlib.colors.Normalize`). Used to convert from time to colour. :param genesis_only: See documentation at top of file. :param axes_object: Axes handle (instance of `matplotlib.axes._subplots.AxesSubplot`). :param basemap_object: Basemap handle (instance of `mpl_toolkits.basemap.Basemap`). """ start_time_colour_matrix = colour_map_object( colour_norm_object(tornado_table[tornado_io.START_TIME_COLUMN].values)) start_x_coords_metres, start_y_coords_metres = basemap_object( tornado_table[tornado_io.START_LNG_COLUMN].values, tornado_table[tornado_io.START_LAT_COLUMN].values) if genesis_only: end_time_colour_matrix = None end_x_coords_metres = None end_y_coords_metres = None else: end_time_colour_matrix = colour_map_object( colour_norm_object( tornado_table[tornado_io.END_TIME_COLUMN].values)) end_x_coords_metres, end_y_coords_metres = basemap_object( tornado_table[tornado_io.END_LNG_COLUMN].values, tornado_table[tornado_io.END_LAT_COLUMN].values) num_tornadoes = len(tornado_table.index) for j in range(num_tornadoes): axes_object.plot( start_x_coords_metres[j], start_y_coords_metres[j], linestyle='None', marker=TORNADO_START_MARKER_TYPE, markersize=TORNADO_MARKER_SIZE, markeredgewidth=TORNADO_MARKER_EDGE_WIDTH, markerfacecolor=plotting_utils.colour_from_numpy_to_tuple( start_time_colour_matrix[j, :-1]), markeredgecolor='k') axes_object.text(start_x_coords_metres[j], start_y_coords_metres[j], tornado_table[SHORT_TORNADO_ID_COLUMN].values[j], fontsize=TORNADO_FONT_SIZE, color='k', horizontalalignment='center', verticalalignment='center') if genesis_only: continue axes_object.plot( end_x_coords_metres[j], end_y_coords_metres[j], linestyle='None', marker=TORNADO_END_MARKER_TYPE, markersize=TORNADO_MARKER_SIZE, markeredgewidth=TORNADO_MARKER_EDGE_WIDTH, markerfacecolor=plotting_utils.colour_from_numpy_to_tuple( end_time_colour_matrix[j, :-1]), markeredgecolor='k') axes_object.text(end_x_coords_metres[j], end_y_coords_metres[j], tornado_table[SHORT_TORNADO_ID_COLUMN].values[j], fontsize=TORNADO_FONT_SIZE, fontweight='bold', color='k', horizontalalignment='center', verticalalignment='center')
def plot_storm_tracks( storm_object_table, axes_object, basemap_object, colour_map_object='random', colour_min_unix_sec=None, colour_max_unix_sec=None, constant_colour=DEFAULT_TRACK_COLOUR, line_width=DEFAULT_TRACK_WIDTH, start_marker_type=DEFAULT_START_MARKER_TYPE, end_marker_type=DEFAULT_END_MARKER_TYPE, start_marker_size=DEFAULT_START_MARKER_SIZE, end_marker_size=DEFAULT_END_MARKER_SIZE): """Plots storm tracks. :param storm_object_table: See doc for `plot_storm_outlines`. :param axes_object: Same. :param basemap_object: Same. :param colour_map_object: See doc for `_process_colour_args`. :param colour_min_unix_sec: Same. :param colour_max_unix_sec: Same. :param constant_colour: Same. :param line_width: Track width. :param start_marker_type: Marker for beginning of each track. If None, markers will not be plotted for beginning of track. :param end_marker_type: Same but for end of track. :param start_marker_size: Size of start-point marker. :param end_marker_size: Size of end-point marker. :return: colour_bar_object: Handle for colour bar. If `colour_map_object is None`, this will also be None. """ x_coords_metres, y_coords_metres = basemap_object( storm_object_table[tracking_utils.CENTROID_LONGITUDE_COLUMN].values, storm_object_table[tracking_utils.CENTROID_LATITUDE_COLUMN].values ) storm_object_table = storm_object_table.assign(**{ tracking_utils.CENTROID_X_COLUMN: x_coords_metres, tracking_utils.CENTROID_Y_COLUMN: y_coords_metres }) rgb_matrix, colour_map_object, colour_norm_object = _process_colour_args( colour_map_object=colour_map_object, colour_min_unix_sec=colour_min_unix_sec, colour_max_unix_sec=colour_max_unix_sec, constant_colour=constant_colour, storm_object_table=storm_object_table ) num_colours = None if rgb_matrix is None else rgb_matrix.shape[0] track_primary_id_strings, object_to_track_indices = numpy.unique( storm_object_table[tracking_utils.PRIMARY_ID_COLUMN].values, return_inverse=True ) num_tracks = len(track_primary_id_strings) for j in range(num_tracks): if colour_map_object is None: this_colour = rgb_matrix[numpy.mod(j, num_colours), :] this_colour = plotting_utils.colour_from_numpy_to_tuple(this_colour) else: this_colour = None these_object_indices = numpy.where(object_to_track_indices == j)[0] storm_object_table_one_track = ( storm_object_table.iloc[these_object_indices] ) _plot_one_track( storm_object_table_one_track=storm_object_table_one_track, axes_object=axes_object, basemap_object=basemap_object, line_width=line_width, line_colour=this_colour, colour_map_object=colour_map_object, colour_norm_object=colour_norm_object) if start_marker_type is not None: _plot_start_or_end_markers( storm_object_table_one_track=storm_object_table_one_track, axes_object=axes_object, plot_at_start=True, marker_type=start_marker_type, marker_size=start_marker_size, track_colour=this_colour, colour_map_object=colour_map_object, colour_norm_object=colour_norm_object) if end_marker_type is not None: _plot_start_or_end_markers( storm_object_table_one_track=storm_object_table_one_track, axes_object=axes_object, plot_at_start=False, marker_type=end_marker_type, marker_size=end_marker_size, track_colour=this_colour, colour_map_object=colour_map_object, colour_norm_object=colour_norm_object) if colour_map_object is None: return None return _add_colour_bar( axes_object=axes_object, basemap_object=basemap_object, colour_map_object=colour_map_object, colour_norm_object=colour_norm_object)
def _plot_linkages_one_storm_object(storm_to_tornadoes_table, storm_object_index, tornado_table, colour_map_object, colour_norm_object, axes_object, basemap_object, max_link_distance_metres=None): """Plots linkages for one storm object. :param storm_to_tornadoes_table: pandas DataFrame returned by `linkage.read_linkage_file`. :param storm_object_index: Will plot linkages for the [k]th storm object, or [k]th row of `storm_to_tornadoes_table`. :param tornado_table: pandas DataFrame returned by `linkage.read_linkage_file`. :param colour_map_object: Colour map (instance of `matplotlib.pyplot.cm`). Text boxes will be coloured by time. :param colour_norm_object: Colour-normalizer (instance of `matplotlib.colors.Normalize`). Used to convert from time to colour. :param axes_object: Axes handle (instance of `matplotlib.axes._subplots.AxesSubplot`). :param basemap_object: Basemap handle (instance of `mpl_toolkits.basemap.Basemap`). :param max_link_distance_metres: See documentation at top of file. """ i = storm_object_index linkage_distances_metres = storm_to_tornadoes_table[ linkage.LINKAGE_DISTANCES_COLUMN].values[i] good_indices = numpy.where( linkage_distances_metres <= max_link_distance_metres)[0] if len(good_indices) == 0: return linked_id_strings = [ storm_to_tornadoes_table[linkage.TORNADO_IDS_COLUMN].values[i][k] for k in good_indices ] linked_short_id_strings = [] for this_id_string in linked_id_strings: these_indices = numpy.where(tornado_table[ tornado_io.TORNADO_ID_COLUMN].values == this_id_string)[0] if len(these_indices) == 0: continue linked_short_id_strings.append( tornado_table[SHORT_TORNADO_ID_COLUMN].values[these_indices[0]]) if len(linked_short_id_strings) == 0: return x_coord_metres, y_coord_metres = basemap_object( storm_to_tornadoes_table[ tracking_utils.CENTROID_LONGITUDE_COLUMN].values[i], storm_to_tornadoes_table[ tracking_utils.CENTROID_LATITUDE_COLUMN].values[i]) bg_colour_numpy = colour_map_object( colour_norm_object(storm_to_tornadoes_table[ tracking_utils.VALID_TIME_COLUMN].values[i])) bounding_box_dict = { 'facecolor': plotting_utils.colour_from_numpy_to_tuple(bg_colour_numpy[:-1]), 'alpha': LINKAGE_BACKGROUND_OPACITY, 'edgecolor': 'k', 'linewidth': 1 } label_string = ','.join(list(set(linked_short_id_strings))) axes_object.text(x_coord_metres, y_coord_metres, label_string, fontsize=LINKAGE_FONT_SIZE, color=LINKAGE_FONT_COLOUR, bbox=bounding_box_dict, horizontalalignment='center', verticalalignment='center', zorder=1e10)