コード例 #1
0
def _plot_storm_outlines_one_time(storm_object_table,
                                  valid_time_unix_sec,
                                  warning_table,
                                  axes_object,
                                  basemap_object,
                                  storm_outline_colour,
                                  storm_outline_opacity,
                                  include_secondary_ids,
                                  output_dir_name,
                                  primary_id_to_track_colour=None,
                                  radar_matrix=None,
                                  radar_field_name=None,
                                  radar_latitudes_deg=None,
                                  radar_longitudes_deg=None,
                                  radar_colour_map_object=None):
    """Plots storm outlines (and may underlay radar data) at one time step.

    M = number of rows in radar grid
    N = number of columns in radar grid
    K = number of storm objects

    If `primary_id_to_track_colour is None`, all storm tracks will be the same
    colour.

    :param storm_object_table: See doc for `storm_plotting.plot_storm_outlines`.
    :param valid_time_unix_sec: Will plot storm outlines only at this time.
        Will plot tracks up to and including this time.
    :param warning_table: None or a pandas table with the following columns.
    warning_table.start_time_unix_sec: Start time.
    warning_table.end_time_unix_sec: End time.
    warning_table.polygon_object_latlng: Polygon (instance of
        `shapely.geometry.Polygon`) with lat-long coordinates of warning
        boundary.

    :param axes_object: See doc for `storm_plotting.plot_storm_outlines`.
    :param basemap_object: Same.
    :param storm_outline_colour: Same.
    :param storm_outline_opacity: Same.
    :param include_secondary_ids: Same.
    :param output_dir_name: See documentation at top of file.
    :param primary_id_to_track_colour: Dictionary created by
        `_assign_colours_to_storms`.  If this is None, all storm tracks will be
        the same colour.
    :param radar_matrix: M-by-N numpy array of radar values.  If
        `radar_matrix is None`, radar data will simply not be plotted.
    :param radar_field_name: [used only if `radar_matrix is not None`]
        See documentation at top of file.
    :param radar_latitudes_deg: [used only if `radar_matrix is not None`]
        length-M numpy array of grid-point latitudes (deg N).
    :param radar_longitudes_deg: [used only if `radar_matrix is not None`]
        length-N numpy array of grid-point longitudes (deg E).
    :param radar_colour_map_object: [used only if `radar_matrix is not None`]
        Colour map (instance of `matplotlib.pyplot.cm`).  If None, will use
        default for the given field.
    """

    # plot_storm_ids = radar_matrix is None or radar_colour_map_object is None
    plot_storm_ids = False

    min_plot_latitude_deg = basemap_object.llcrnrlat
    max_plot_latitude_deg = basemap_object.urcrnrlat
    min_plot_longitude_deg = basemap_object.llcrnrlon
    max_plot_longitude_deg = basemap_object.urcrnrlon

    plotting_utils.plot_coastlines(basemap_object=basemap_object,
                                   axes_object=axes_object,
                                   line_colour=BORDER_COLOUR)
    plotting_utils.plot_countries(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  line_colour=BORDER_COLOUR)
    plotting_utils.plot_states_and_provinces(basemap_object=basemap_object,
                                             axes_object=axes_object,
                                             line_colour=BORDER_COLOUR)
    plotting_utils.plot_parallels(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_parallels=NUM_PARALLELS)
    plotting_utils.plot_meridians(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_meridians=NUM_MERIDIANS)

    if radar_matrix is not None:
        custom_colour_map = radar_colour_map_object is not None

        good_indices = numpy.where(
            numpy.logical_and(radar_latitudes_deg >= min_plot_latitude_deg,
                              radar_latitudes_deg <= max_plot_latitude_deg))[0]

        radar_latitudes_deg = radar_latitudes_deg[good_indices]
        radar_matrix = radar_matrix[good_indices, :]

        good_indices = numpy.where(
            numpy.logical_and(
                radar_longitudes_deg >= min_plot_longitude_deg,
                radar_longitudes_deg <= max_plot_longitude_deg))[0]

        radar_longitudes_deg = radar_longitudes_deg[good_indices]
        radar_matrix = radar_matrix[:, good_indices]

        latitude_spacing_deg = radar_latitudes_deg[1] - radar_latitudes_deg[0]
        longitude_spacing_deg = (radar_longitudes_deg[1] -
                                 radar_longitudes_deg[0])

        if radar_colour_map_object is None:
            colour_map_object, colour_norm_object = (
                radar_plotting.get_default_colour_scheme(radar_field_name))
        else:
            colour_map_object = radar_colour_map_object
            colour_norm_object = radar_plotting.get_default_colour_scheme(
                radar_field_name)[-1]

            this_ratio = radar_plotting._field_to_plotting_units(
                field_matrix=1., field_name=radar_field_name)

            colour_norm_object = pyplot.Normalize(
                colour_norm_object.vmin / this_ratio,
                colour_norm_object.vmax / this_ratio)

        radar_plotting.plot_latlng_grid(
            field_matrix=radar_matrix,
            field_name=radar_field_name,
            axes_object=axes_object,
            min_grid_point_latitude_deg=numpy.min(radar_latitudes_deg),
            min_grid_point_longitude_deg=numpy.min(radar_longitudes_deg),
            latitude_spacing_deg=latitude_spacing_deg,
            longitude_spacing_deg=longitude_spacing_deg,
            colour_map_object=colour_map_object,
            colour_norm_object=colour_norm_object)

        latitude_range_deg = max_plot_latitude_deg - min_plot_latitude_deg
        longitude_range_deg = max_plot_longitude_deg - min_plot_longitude_deg

        if latitude_range_deg > longitude_range_deg:
            orientation_string = 'vertical'
        else:
            orientation_string = 'horizontal'

        colour_bar_object = plotting_utils.plot_colour_bar(
            axes_object_or_matrix=axes_object,
            data_matrix=radar_matrix,
            colour_map_object=colour_map_object,
            colour_norm_object=colour_norm_object,
            orientation_string=orientation_string,
            padding=0.05,
            extend_min=radar_field_name in radar_plotting.SHEAR_VORT_DIV_NAMES,
            extend_max=True,
            fraction_of_axis_length=1.)

        radar_field_name_verbose = radar_utils.field_name_to_verbose(
            field_name=radar_field_name, include_units=True)
        radar_field_name_verbose = radar_field_name_verbose.replace(
            'm ASL', 'kft ASL')
        colour_bar_object.set_label(radar_field_name_verbose)

        if custom_colour_map:
            tick_values = colour_bar_object.get_ticks()
            tick_label_strings = ['{0:.1f}'.format(v) for v in tick_values]
            colour_bar_object.set_ticks(tick_values)
            colour_bar_object.set_ticklabels(tick_label_strings)

    valid_time_rows = numpy.where(storm_object_table[
        tracking_utils.VALID_TIME_COLUMN].values == valid_time_unix_sec)[0]

    this_colour = matplotlib.colors.to_rgba(storm_outline_colour,
                                            storm_outline_opacity)

    storm_plotting.plot_storm_outlines(
        storm_object_table=storm_object_table.iloc[valid_time_rows],
        axes_object=axes_object,
        basemap_object=basemap_object,
        line_colour=this_colour)

    if plot_storm_ids:
        storm_plotting.plot_storm_ids(
            storm_object_table=storm_object_table.iloc[valid_time_rows],
            axes_object=axes_object,
            basemap_object=basemap_object,
            plot_near_centroids=False,
            include_secondary_ids=include_secondary_ids,
            font_colour=storm_plotting.DEFAULT_FONT_COLOUR)

    if warning_table is not None:
        warning_indices = numpy.where(
            numpy.logical_and(
                warning_table[WARNING_START_TIME_KEY].values <=
                valid_time_unix_sec, warning_table[WARNING_END_TIME_KEY].values
                >= valid_time_unix_sec))[0]

        for k in warning_indices:
            this_vertex_dict = polygons.polygon_object_to_vertex_arrays(
                warning_table[WARNING_LATLNG_POLYGON_KEY].values[k])
            these_latitudes_deg = this_vertex_dict[polygons.EXTERIOR_Y_COLUMN]
            these_longitudes_deg = this_vertex_dict[polygons.EXTERIOR_X_COLUMN]

            these_latitude_flags = numpy.logical_and(
                these_latitudes_deg >= min_plot_latitude_deg,
                these_latitudes_deg <= max_plot_latitude_deg)
            these_longitude_flags = numpy.logical_and(
                these_longitudes_deg >= min_plot_longitude_deg,
                these_longitudes_deg <= max_plot_longitude_deg)
            these_coord_flags = numpy.logical_and(these_latitude_flags,
                                                  these_longitude_flags)

            if not numpy.any(these_coord_flags):
                continue

            these_x_metres, these_y_metres = basemap_object(
                these_longitudes_deg, these_latitudes_deg)
            axes_object.plot(these_x_metres,
                             these_y_metres,
                             color=this_colour,
                             linestyle='dashed',
                             linewidth=storm_plotting.DEFAULT_POLYGON_WIDTH)

            axes_object.text(numpy.mean(these_x_metres),
                             numpy.mean(these_y_metres),
                             'W{0:d}'.format(k),
                             fontsize=storm_plotting.DEFAULT_FONT_SIZE,
                             fontweight='bold',
                             color=this_colour,
                             horizontalalignment='center',
                             verticalalignment='center')

            these_sec_id_strings = (
                warning_table[LINKED_SECONDARY_IDS_KEY].values[k])
            if len(these_sec_id_strings) == 0:
                continue

            these_object_indices = numpy.array([], dtype=int)

            for this_sec_id_string in these_sec_id_strings:
                these_subindices = numpy.where(
                    storm_object_table[tracking_utils.SECONDARY_ID_COLUMN].
                    values[valid_time_rows] == this_sec_id_string)[0]

                these_object_indices = numpy.concatenate(
                    (these_object_indices, valid_time_rows[these_subindices]))

            for i in these_object_indices:
                this_vertex_dict = 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[polygons.EXTERIOR_X_COLUMN],
                    this_vertex_dict[polygons.EXTERIOR_Y_COLUMN])

                axes_object.text(numpy.mean(these_x_metres),
                                 numpy.mean(these_y_metres),
                                 'W{0:d}'.format(k),
                                 fontsize=storm_plotting.DEFAULT_FONT_SIZE,
                                 fontweight='bold',
                                 color=this_colour,
                                 horizontalalignment='center',
                                 verticalalignment='center')

    if primary_id_to_track_colour is None:
        storm_plotting.plot_storm_tracks(storm_object_table=storm_object_table,
                                         axes_object=axes_object,
                                         basemap_object=basemap_object,
                                         colour_map_object=None,
                                         constant_colour=DEFAULT_TRACK_COLOUR)
    else:
        for this_primary_id_string in primary_id_to_track_colour:
            this_storm_object_table = storm_object_table.loc[
                storm_object_table[tracking_utils.PRIMARY_ID_COLUMN] ==
                this_primary_id_string]

            if len(this_storm_object_table.index) == 0:
                continue

            storm_plotting.plot_storm_tracks(
                storm_object_table=this_storm_object_table,
                axes_object=axes_object,
                basemap_object=basemap_object,
                colour_map_object=None,
                constant_colour=primary_id_to_track_colour[
                    this_primary_id_string])

    nice_time_string = time_conversion.unix_sec_to_string(
        valid_time_unix_sec, NICE_TIME_FORMAT)

    abbrev_time_string = time_conversion.unix_sec_to_string(
        valid_time_unix_sec, FILE_NAME_TIME_FORMAT)

    pyplot.title('Storm objects at {0:s}'.format(nice_time_string))
    output_file_name = '{0:s}/storm_outlines_{1:s}.jpg'.format(
        output_dir_name, abbrev_time_string)

    print('Saving figure to: "{0:s}"...'.format(output_file_name))
    pyplot.savefig(output_file_name,
                   dpi=FIGURE_RESOLUTION_DPI,
                   pad_inches=0,
                   bbox_inches='tight')
    pyplot.close()
コード例 #2
0
def _plot_storm_outlines_one_time(storm_object_table,
                                  valid_time_unix_sec,
                                  axes_object,
                                  basemap_object,
                                  storm_colour,
                                  storm_opacity,
                                  include_secondary_ids,
                                  output_dir_name,
                                  radar_matrix=None,
                                  radar_field_name=None,
                                  radar_latitudes_deg=None,
                                  radar_longitudes_deg=None):
    """Plots storm outlines (and may underlay radar data) at one time step.

    M = number of rows in radar grid
    N = number of columns in radar grid
    K = number of storm objects

    :param storm_object_table: See doc for `storm_plotting.plot_storm_outlines`.
    :param valid_time_unix_sec: Will plot storm outlines only at this time.
        Will plot tracks up to and including this time.
    :param axes_object: Same.
    :param basemap_object: Same.
    :param storm_colour: Same.
    :param storm_opacity: Same.
    :param include_secondary_ids: Same.
    :param output_dir_name: See documentation at top of file.
    :param radar_matrix: M-by-N numpy array of radar values.  If
        `radar_matrix is None`, radar data will simply not be plotted.
    :param radar_field_name: [used only if `radar_matrix is not None`]
        See documentation at top of file.
    :param radar_latitudes_deg: [used only if `radar_matrix is not None`]
        length-M numpy array of grid-point latitudes (deg N).
    :param radar_longitudes_deg: [used only if `radar_matrix is not None`]
        length-N numpy array of grid-point longitudes (deg E).
    """

    min_plot_latitude_deg = basemap_object.llcrnrlat
    max_plot_latitude_deg = basemap_object.urcrnrlat
    min_plot_longitude_deg = basemap_object.llcrnrlon
    max_plot_longitude_deg = basemap_object.urcrnrlon

    plotting_utils.plot_coastlines(basemap_object=basemap_object,
                                   axes_object=axes_object,
                                   line_colour=BORDER_COLOUR)

    plotting_utils.plot_countries(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  line_colour=BORDER_COLOUR)

    plotting_utils.plot_states_and_provinces(basemap_object=basemap_object,
                                             axes_object=axes_object,
                                             line_colour=BORDER_COLOUR)

    plotting_utils.plot_parallels(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_parallels=NUM_PARALLELS)

    plotting_utils.plot_meridians(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_meridians=NUM_MERIDIANS)

    if radar_matrix is not None:
        good_indices = numpy.where(
            numpy.logical_and(radar_latitudes_deg >= min_plot_latitude_deg,
                              radar_latitudes_deg <= max_plot_latitude_deg))[0]

        radar_latitudes_deg = radar_latitudes_deg[good_indices]
        radar_matrix = radar_matrix[good_indices, :]

        good_indices = numpy.where(
            numpy.logical_and(
                radar_longitudes_deg >= min_plot_longitude_deg,
                radar_longitudes_deg <= max_plot_longitude_deg))[0]

        radar_longitudes_deg = radar_longitudes_deg[good_indices]
        radar_matrix = radar_matrix[:, good_indices]

        latitude_spacing_deg = radar_latitudes_deg[1] - radar_latitudes_deg[0]
        longitude_spacing_deg = (radar_longitudes_deg[1] -
                                 radar_longitudes_deg[0])

        radar_plotting.plot_latlng_grid(
            field_matrix=radar_matrix,
            field_name=radar_field_name,
            axes_object=axes_object,
            min_grid_point_latitude_deg=numpy.min(radar_latitudes_deg),
            min_grid_point_longitude_deg=numpy.min(radar_longitudes_deg),
            latitude_spacing_deg=latitude_spacing_deg,
            longitude_spacing_deg=longitude_spacing_deg)

        colour_map_object, colour_norm_object = (
            radar_plotting.get_default_colour_scheme(radar_field_name))

        latitude_range_deg = max_plot_latitude_deg - min_plot_latitude_deg
        longitude_range_deg = max_plot_longitude_deg - min_plot_longitude_deg

        if latitude_range_deg > longitude_range_deg:
            orientation_string = 'vertical'
        else:
            orientation_string = 'horizontal'

        colour_bar_object = plotting_utils.plot_colour_bar(
            axes_object_or_matrix=axes_object,
            data_matrix=radar_matrix,
            colour_map_object=colour_map_object,
            colour_norm_object=colour_norm_object,
            orientation_string=orientation_string,
            extend_min=radar_field_name in radar_plotting.SHEAR_VORT_DIV_NAMES,
            extend_max=True,
            fraction_of_axis_length=0.9)

        colour_bar_object.set_label(
            radar_plotting.FIELD_NAME_TO_VERBOSE_DICT[radar_field_name])

    valid_time_rows = numpy.where(storm_object_table[
        tracking_utils.VALID_TIME_COLUMN].values == valid_time_unix_sec)[0]

    line_colour = matplotlib.colors.to_rgba(storm_colour, storm_opacity)

    storm_plotting.plot_storm_outlines(
        storm_object_table=storm_object_table.iloc[valid_time_rows],
        axes_object=axes_object,
        basemap_object=basemap_object,
        line_colour=line_colour)

    storm_plotting.plot_storm_ids(
        storm_object_table=storm_object_table.iloc[valid_time_rows],
        axes_object=axes_object,
        basemap_object=basemap_object,
        plot_near_centroids=False,
        include_secondary_ids=include_secondary_ids,
        font_colour=storm_plotting.DEFAULT_FONT_COLOUR)

    storm_plotting.plot_storm_tracks(storm_object_table=storm_object_table,
                                     axes_object=axes_object,
                                     basemap_object=basemap_object,
                                     colour_map_object=None,
                                     line_colour=TRACK_COLOUR)

    nice_time_string = time_conversion.unix_sec_to_string(
        valid_time_unix_sec, NICE_TIME_FORMAT)

    abbrev_time_string = time_conversion.unix_sec_to_string(
        valid_time_unix_sec, FILE_NAME_TIME_FORMAT)

    pyplot.title('Storm objects at {0:s}'.format(nice_time_string))
    output_file_name = '{0:s}/storm_outlines_{1:s}.jpg'.format(
        output_dir_name, abbrev_time_string)

    print('Saving figure to: "{0:s}"...'.format(output_file_name))
    pyplot.savefig(output_file_name, dpi=FIGURE_RESOLUTION_DPI)
    pyplot.close()

    imagemagick_utils.trim_whitespace(input_file_name=output_file_name,
                                      output_file_name=output_file_name)
コード例 #3
0
def _plot_tornado_and_radar(top_myrorss_dir_name, radar_field_name,
                            radar_height_m_asl, spc_date_string, tornado_table,
                            tornado_row, output_file_name):
    """Plots one unlinked tornado with radar field.

    :param top_myrorss_dir_name: See documentation at top of file.
    :param radar_field_name: Same.
    :param radar_height_m_asl: Same.
    :param spc_date_string: SPC date for linkage file (format "yyyymmdd").
    :param tornado_table: pandas DataFrame created by
        `linkage._read_input_tornado_reports`.
    :param tornado_row: Will plot only tornado in [j]th row of table, where j =
        `tornado_row`.
    :param output_file_name: Path to output file.  Figure will be saved here.
    """

    tornado_time_unix_sec = tornado_table[
        linkage.EVENT_TIME_COLUMN].values[tornado_row]

    radar_time_unix_sec = number_rounding.round_to_nearest(
        tornado_time_unix_sec, RADAR_TIME_INTERVAL_SEC)

    radar_spc_date_string = time_conversion.time_to_spc_date_string(
        radar_time_unix_sec)

    radar_file_name = myrorss_and_mrms_io.find_raw_file(
        top_directory_name=top_myrorss_dir_name,
        spc_date_string=radar_spc_date_string,
        unix_time_sec=radar_time_unix_sec,
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        field_name=radar_field_name,
        height_m_asl=radar_height_m_asl,
        raise_error_if_missing=spc_date_string == radar_spc_date_string)

    if not os.path.isfile(radar_file_name):
        first_radar_time_unix_sec = number_rounding.ceiling_to_nearest(
            time_conversion.get_start_of_spc_date(spc_date_string),
            RADAR_TIME_INTERVAL_SEC)

        last_radar_time_unix_sec = number_rounding.floor_to_nearest(
            time_conversion.get_end_of_spc_date(spc_date_string),
            RADAR_TIME_INTERVAL_SEC)

        radar_time_unix_sec = max(
            [radar_time_unix_sec, first_radar_time_unix_sec])

        radar_time_unix_sec = min(
            [radar_time_unix_sec, last_radar_time_unix_sec])

        radar_file_name = myrorss_and_mrms_io.find_raw_file(
            top_directory_name=top_myrorss_dir_name,
            spc_date_string=spc_date_string,
            unix_time_sec=radar_time_unix_sec,
            data_source=radar_utils.MYRORSS_SOURCE_ID,
            field_name=radar_field_name,
            height_m_asl=radar_height_m_asl,
            raise_error_if_missing=True)

    radar_metadata_dict = myrorss_and_mrms_io.read_metadata_from_raw_file(
        netcdf_file_name=radar_file_name,
        data_source=radar_utils.MYRORSS_SOURCE_ID)

    sparse_grid_table = (myrorss_and_mrms_io.read_data_from_sparse_grid_file(
        netcdf_file_name=radar_file_name,
        field_name_orig=radar_metadata_dict[
            myrorss_and_mrms_io.FIELD_NAME_COLUMN_ORIG],
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        sentinel_values=radar_metadata_dict[radar_utils.SENTINEL_VALUE_COLUMN])
                         )

    radar_matrix, grid_point_latitudes_deg, grid_point_longitudes_deg = (
        radar_s2f.sparse_to_full_grid(sparse_grid_table=sparse_grid_table,
                                      metadata_dict=radar_metadata_dict))

    radar_matrix = numpy.flip(radar_matrix, axis=0)
    grid_point_latitudes_deg = grid_point_latitudes_deg[::-1]

    axes_object, basemap_object = (
        plotting_utils.create_equidist_cylindrical_map(
            min_latitude_deg=numpy.min(grid_point_latitudes_deg),
            max_latitude_deg=numpy.max(grid_point_latitudes_deg),
            min_longitude_deg=numpy.min(grid_point_longitudes_deg),
            max_longitude_deg=numpy.max(grid_point_longitudes_deg),
            resolution_string='i')[1:])

    plotting_utils.plot_coastlines(basemap_object=basemap_object,
                                   axes_object=axes_object,
                                   line_colour=BORDER_COLOUR)

    plotting_utils.plot_countries(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  line_colour=BORDER_COLOUR)

    plotting_utils.plot_states_and_provinces(basemap_object=basemap_object,
                                             axes_object=axes_object,
                                             line_colour=BORDER_COLOUR)

    plotting_utils.plot_parallels(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_parallels=NUM_PARALLELS)

    plotting_utils.plot_meridians(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_meridians=NUM_MERIDIANS)

    radar_plotting.plot_latlng_grid(
        field_matrix=radar_matrix,
        field_name=radar_field_name,
        axes_object=axes_object,
        min_grid_point_latitude_deg=numpy.min(grid_point_latitudes_deg),
        min_grid_point_longitude_deg=numpy.min(grid_point_longitudes_deg),
        latitude_spacing_deg=numpy.diff(grid_point_latitudes_deg[:2])[0],
        longitude_spacing_deg=numpy.diff(grid_point_longitudes_deg[:2])[0])

    tornado_latitude_deg = tornado_table[
        linkage.EVENT_LATITUDE_COLUMN].values[tornado_row]

    tornado_longitude_deg = tornado_table[
        linkage.EVENT_LONGITUDE_COLUMN].values[tornado_row]

    axes_object.plot(tornado_longitude_deg,
                     tornado_latitude_deg,
                     linestyle='None',
                     marker=TORNADO_MARKER_TYPE,
                     markersize=TORNADO_MARKER_SIZE,
                     markeredgewidth=TORNADO_MARKER_EDGE_WIDTH,
                     markerfacecolor=plotting_utils.colour_from_numpy_to_tuple(
                         TORNADO_MARKER_COLOUR),
                     markeredgecolor=plotting_utils.colour_from_numpy_to_tuple(
                         TORNADO_MARKER_COLOUR))

    tornado_time_string = time_conversion.unix_sec_to_string(
        tornado_time_unix_sec, TIME_FORMAT)

    title_string = (
        'Unlinked tornado at {0:s}, {1:.2f} deg N, {2:.2f} deg E').format(
            tornado_time_string, tornado_latitude_deg, tornado_longitude_deg)

    pyplot.title(title_string, fontsize=TITLE_FONT_SIZE)

    print('Saving figure to: "{0:s}"...'.format(output_file_name))
    pyplot.savefig(output_file_name, dpi=FIGURE_RESOLUTION_DPI)
    pyplot.close()

    imagemagick_utils.trim_whitespace(input_file_name=output_file_name,
                                      output_file_name=output_file_name)
コード例 #4
0
def _plot_one_example_one_time(storm_object_table, full_id_string,
                               valid_time_unix_sec, tornado_table,
                               top_myrorss_dir_name, radar_field_name,
                               radar_height_m_asl, latitude_limits_deg,
                               longitude_limits_deg):
    """Plots one example with surrounding context at one time.

    :param storm_object_table: pandas DataFrame, containing only storm objects
        at one time with the relevant primary ID.  Columns are documented in
        `storm_tracking_io.write_file`.
    :param full_id_string: Full ID of storm of interest.
    :param valid_time_unix_sec: Valid time.
    :param tornado_table: pandas DataFrame created by
        `linkage._read_input_tornado_reports`.
    :param top_myrorss_dir_name: See documentation at top of file.
    :param radar_field_name: Same.
    :param radar_height_m_asl: Same.
    :param latitude_limits_deg: See doc for `_get_plotting_limits`.
    :param longitude_limits_deg: Same.
    """

    min_plot_latitude_deg = latitude_limits_deg[0]
    max_plot_latitude_deg = latitude_limits_deg[1]
    min_plot_longitude_deg = longitude_limits_deg[0]
    max_plot_longitude_deg = longitude_limits_deg[1]

    radar_file_name = myrorss_and_mrms_io.find_raw_file(
        top_directory_name=top_myrorss_dir_name,
        spc_date_string=time_conversion.time_to_spc_date_string(
            valid_time_unix_sec),
        unix_time_sec=valid_time_unix_sec,
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        field_name=radar_field_name,
        height_m_asl=radar_height_m_asl,
        raise_error_if_missing=True)

    print('Reading data from: "{0:s}"...'.format(radar_file_name))

    radar_metadata_dict = myrorss_and_mrms_io.read_metadata_from_raw_file(
        netcdf_file_name=radar_file_name,
        data_source=radar_utils.MYRORSS_SOURCE_ID)

    sparse_grid_table = (myrorss_and_mrms_io.read_data_from_sparse_grid_file(
        netcdf_file_name=radar_file_name,
        field_name_orig=radar_metadata_dict[
            myrorss_and_mrms_io.FIELD_NAME_COLUMN_ORIG],
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        sentinel_values=radar_metadata_dict[radar_utils.SENTINEL_VALUE_COLUMN])
                         )

    radar_matrix, grid_point_latitudes_deg, grid_point_longitudes_deg = (
        radar_s2f.sparse_to_full_grid(sparse_grid_table=sparse_grid_table,
                                      metadata_dict=radar_metadata_dict))

    radar_matrix = numpy.flip(radar_matrix, axis=0)
    grid_point_latitudes_deg = grid_point_latitudes_deg[::-1]

    axes_object, basemap_object = (
        plotting_utils.create_equidist_cylindrical_map(
            min_latitude_deg=min_plot_latitude_deg,
            max_latitude_deg=max_plot_latitude_deg,
            min_longitude_deg=min_plot_longitude_deg,
            max_longitude_deg=max_plot_longitude_deg,
            resolution_string='i')[1:])

    plotting_utils.plot_coastlines(basemap_object=basemap_object,
                                   axes_object=axes_object,
                                   line_colour=BORDER_COLOUR)

    plotting_utils.plot_countries(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  line_colour=BORDER_COLOUR)

    plotting_utils.plot_states_and_provinces(basemap_object=basemap_object,
                                             axes_object=axes_object,
                                             line_colour=BORDER_COLOUR)

    plotting_utils.plot_parallels(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_parallels=NUM_PARALLELS)

    plotting_utils.plot_meridians(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_meridians=NUM_MERIDIANS)

    radar_plotting.plot_latlng_grid(
        field_matrix=radar_matrix,
        field_name=radar_field_name,
        axes_object=axes_object,
        min_grid_point_latitude_deg=numpy.min(grid_point_latitudes_deg),
        min_grid_point_longitude_deg=numpy.min(grid_point_longitudes_deg),
        latitude_spacing_deg=numpy.diff(grid_point_latitudes_deg[:2])[0],
        longitude_spacing_deg=numpy.diff(grid_point_longitudes_deg[:2])[0])

    colour_map_object, colour_norm_object = (
        radar_plotting.get_default_colour_scheme(radar_field_name))

    plotting_utils.plot_colour_bar(axes_object_or_matrix=axes_object,
                                   data_matrix=radar_matrix,
                                   colour_map_object=colour_map_object,
                                   colour_norm_object=colour_norm_object,
                                   orientation_string='horizontal',
                                   extend_min=False,
                                   extend_max=True,
                                   fraction_of_axis_length=0.8)

    first_list, second_list = temporal_tracking.full_to_partial_ids(
        [full_id_string])
    primary_id_string = first_list[0]
    secondary_id_string = second_list[0]

    # Plot outlines of unrelated storms (with different primary IDs).
    this_storm_object_table = storm_object_table.loc[storm_object_table[
        tracking_utils.PRIMARY_ID_COLUMN] != primary_id_string]

    storm_plotting.plot_storm_outlines(
        storm_object_table=this_storm_object_table,
        axes_object=axes_object,
        basemap_object=basemap_object,
        line_width=2,
        line_colour='k',
        line_style='dashed')

    # Plot outlines of related storms (with the same primary ID).
    this_storm_object_table = storm_object_table.loc[
        (storm_object_table[tracking_utils.PRIMARY_ID_COLUMN] ==
         primary_id_string) & (storm_object_table[
             tracking_utils.SECONDARY_ID_COLUMN] != secondary_id_string)]

    this_num_storm_objects = len(this_storm_object_table.index)

    if this_num_storm_objects > 0:
        storm_plotting.plot_storm_outlines(
            storm_object_table=this_storm_object_table,
            axes_object=axes_object,
            basemap_object=basemap_object,
            line_width=2,
            line_colour='k',
            line_style='solid')

        for j in range(len(this_storm_object_table)):
            axes_object.text(
                this_storm_object_table[
                    tracking_utils.CENTROID_LONGITUDE_COLUMN].values[j],
                this_storm_object_table[
                    tracking_utils.CENTROID_LATITUDE_COLUMN].values[j],
                'P',
                fontsize=FONT_SIZE,
                color=FONT_COLOUR,
                fontweight='bold',
                horizontalalignment='center',
                verticalalignment='center')

    # Plot outline of storm of interest (same secondary ID).
    this_storm_object_table = storm_object_table.loc[storm_object_table[
        tracking_utils.SECONDARY_ID_COLUMN] == secondary_id_string]

    storm_plotting.plot_storm_outlines(
        storm_object_table=this_storm_object_table,
        axes_object=axes_object,
        basemap_object=basemap_object,
        line_width=4,
        line_colour='k',
        line_style='solid')

    this_num_storm_objects = len(this_storm_object_table.index)

    plot_forecast = (this_num_storm_objects > 0 and FORECAST_PROBABILITY_COLUMN
                     in list(this_storm_object_table))

    if plot_forecast:
        this_polygon_object_latlng = this_storm_object_table[
            tracking_utils.LATLNG_POLYGON_COLUMN].values[0]

        this_latitude_deg = numpy.min(
            numpy.array(this_polygon_object_latlng.exterior.xy[1]))

        this_longitude_deg = this_storm_object_table[
            tracking_utils.CENTROID_LONGITUDE_COLUMN].values[0]

        label_string = 'Prob = {0:.3f}\nat {1:s}'.format(
            this_storm_object_table[FORECAST_PROBABILITY_COLUMN].values[0],
            time_conversion.unix_sec_to_string(valid_time_unix_sec,
                                               TORNADO_TIME_FORMAT))

        bounding_box_dict = {
            'facecolor':
            plotting_utils.colour_from_numpy_to_tuple(
                PROBABILITY_BACKGROUND_COLOUR),
            'alpha':
            PROBABILITY_BACKGROUND_OPACITY,
            'edgecolor':
            'k',
            'linewidth':
            1
        }

        axes_object.text(this_longitude_deg,
                         this_latitude_deg,
                         label_string,
                         fontsize=FONT_SIZE,
                         color=plotting_utils.colour_from_numpy_to_tuple(
                             PROBABILITY_FONT_COLOUR),
                         fontweight='bold',
                         bbox=bounding_box_dict,
                         horizontalalignment='center',
                         verticalalignment='top',
                         zorder=1e10)

    tornado_latitudes_deg = tornado_table[linkage.EVENT_LATITUDE_COLUMN].values
    tornado_longitudes_deg = tornado_table[
        linkage.EVENT_LONGITUDE_COLUMN].values

    tornado_times_unix_sec = tornado_table[linkage.EVENT_TIME_COLUMN].values
    tornado_time_strings = [
        time_conversion.unix_sec_to_string(t, TORNADO_TIME_FORMAT)
        for t in tornado_times_unix_sec
    ]

    axes_object.plot(tornado_longitudes_deg,
                     tornado_latitudes_deg,
                     linestyle='None',
                     marker=TORNADO_MARKER_TYPE,
                     markersize=TORNADO_MARKER_SIZE,
                     markeredgewidth=TORNADO_MARKER_EDGE_WIDTH,
                     markerfacecolor=plotting_utils.colour_from_numpy_to_tuple(
                         TORNADO_MARKER_COLOUR),
                     markeredgecolor=plotting_utils.colour_from_numpy_to_tuple(
                         TORNADO_MARKER_COLOUR))

    num_tornadoes = len(tornado_latitudes_deg)

    for j in range(num_tornadoes):
        axes_object.text(tornado_longitudes_deg[j] + 0.02,
                         tornado_latitudes_deg[j] - 0.02,
                         tornado_time_strings[j],
                         fontsize=FONT_SIZE,
                         color=FONT_COLOUR,
                         fontweight='bold',
                         horizontalalignment='left',
                         verticalalignment='top')
コード例 #5
0
def _plot_one_field(reflectivity_matrix_dbz, latitudes_deg, longitudes_deg,
                    add_colour_bar, panel_letter, output_file_name):
    """Plots reflectivity field from one dataset.

    :param reflectivity_matrix_dbz: See doc for `_read_file`.
    :param latitudes_deg: Same.
    :param longitudes_deg: Same.
    :param add_colour_bar: Boolean flag.
    :param panel_letter: Panel letter (will be printed at top left of figure).
    :param output_file_name: Path to output file (figure will be saved here).
    """

    (figure_object, axes_object,
     basemap_object) = plotting_utils.create_equidist_cylindrical_map(
         min_latitude_deg=numpy.min(latitudes_deg),
         max_latitude_deg=numpy.max(latitudes_deg),
         min_longitude_deg=numpy.min(longitudes_deg),
         max_longitude_deg=numpy.max(longitudes_deg),
         resolution_string='i')

    plotting_utils.plot_coastlines(basemap_object=basemap_object,
                                   axes_object=axes_object,
                                   line_colour=BORDER_COLOUR)
    plotting_utils.plot_countries(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  line_colour=BORDER_COLOUR)
    plotting_utils.plot_states_and_provinces(basemap_object=basemap_object,
                                             axes_object=axes_object,
                                             line_colour=BORDER_COLOUR)
    plotting_utils.plot_parallels(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_parallels=NUM_PARALLELS)
    plotting_utils.plot_meridians(basemap_object=basemap_object,
                                  axes_object=axes_object,
                                  num_meridians=NUM_MERIDIANS)

    radar_plotting.plot_latlng_grid(
        field_matrix=reflectivity_matrix_dbz,
        field_name=RADAR_FIELD_NAME,
        axes_object=axes_object,
        min_grid_point_latitude_deg=numpy.min(latitudes_deg),
        min_grid_point_longitude_deg=numpy.min(longitudes_deg),
        latitude_spacing_deg=latitudes_deg[1] - latitudes_deg[0],
        longitude_spacing_deg=longitudes_deg[1] - longitudes_deg[0])

    if add_colour_bar:
        colour_map_object, colour_norm_object = (
            radar_plotting.get_default_colour_scheme(RADAR_FIELD_NAME))

        plotting_utils.plot_colour_bar(axes_object_or_matrix=axes_object,
                                       data_matrix=reflectivity_matrix_dbz,
                                       colour_map_object=colour_map_object,
                                       colour_norm_object=colour_norm_object,
                                       orientation_string='horizontal',
                                       padding=0.05,
                                       extend_min=False,
                                       extend_max=True,
                                       fraction_of_axis_length=1.)

    plotting_utils.label_axes(axes_object=axes_object,
                              label_string='({0:s})'.format(panel_letter),
                              y_coord_normalized=1.03)

    print('Saving figure to: "{0:s}"...'.format(output_file_name))
    figure_object.savefig(output_file_name,
                          dpi=FIGURE_RESOLUTION_DPI,
                          pad_inches=0,
                          bbox_inches='tight')
    pyplot.close(figure_object)
コード例 #6
0
def _plot_one_example_one_time(
        storm_object_table, full_id_string, valid_time_unix_sec,
        tornado_table, top_myrorss_dir_name, radar_field_name,
        radar_height_m_asl, latitude_limits_deg, longitude_limits_deg):
    """Plots one example with surrounding context at one time.

    :param storm_object_table: pandas DataFrame, containing only storm objects
        at one time with the relevant primary ID.  Columns are documented in
        `storm_tracking_io.write_file`.
    :param full_id_string: Full ID of storm of interest.
    :param valid_time_unix_sec: Valid time.
    :param tornado_table: pandas DataFrame created by
        `linkage._read_input_tornado_reports`.
    :param top_myrorss_dir_name: See documentation at top of file.
    :param radar_field_name: Same.
    :param radar_height_m_asl: Same.
    :param latitude_limits_deg: See doc for `_get_plotting_limits`.
    :param longitude_limits_deg: Same.
    """

    min_plot_latitude_deg = latitude_limits_deg[0]
    max_plot_latitude_deg = latitude_limits_deg[1]
    min_plot_longitude_deg = longitude_limits_deg[0]
    max_plot_longitude_deg = longitude_limits_deg[1]

    radar_file_name = myrorss_and_mrms_io.find_raw_file_inexact_time(
        top_directory_name=top_myrorss_dir_name,
        desired_time_unix_sec=valid_time_unix_sec,
        spc_date_string=time_conversion.time_to_spc_date_string(
            valid_time_unix_sec),
        data_source=radar_utils.MYRORSS_SOURCE_ID,
        field_name=radar_field_name, height_m_asl=radar_height_m_asl,
        max_time_offset_sec=
        myrorss_and_mrms_io.DEFAULT_MAX_TIME_OFFSET_FOR_NON_SHEAR_SEC,
        raise_error_if_missing=True)

    print('Reading data from: "{0:s}"...'.format(radar_file_name))

    radar_metadata_dict = myrorss_and_mrms_io.read_metadata_from_raw_file(
        netcdf_file_name=radar_file_name,
        data_source=radar_utils.MYRORSS_SOURCE_ID)

    sparse_grid_table = (
        myrorss_and_mrms_io.read_data_from_sparse_grid_file(
            netcdf_file_name=radar_file_name,
            field_name_orig=radar_metadata_dict[
                myrorss_and_mrms_io.FIELD_NAME_COLUMN_ORIG],
            data_source=radar_utils.MYRORSS_SOURCE_ID,
            sentinel_values=radar_metadata_dict[
                radar_utils.SENTINEL_VALUE_COLUMN]
        )
    )

    radar_matrix, grid_point_latitudes_deg, grid_point_longitudes_deg = (
        radar_s2f.sparse_to_full_grid(
            sparse_grid_table=sparse_grid_table,
            metadata_dict=radar_metadata_dict)
    )

    radar_matrix = numpy.flip(radar_matrix, axis=0)
    grid_point_latitudes_deg = grid_point_latitudes_deg[::-1]

    axes_object, basemap_object = (
        plotting_utils.create_equidist_cylindrical_map(
            min_latitude_deg=min_plot_latitude_deg,
            max_latitude_deg=max_plot_latitude_deg,
            min_longitude_deg=min_plot_longitude_deg,
            max_longitude_deg=max_plot_longitude_deg, resolution_string='h'
        )[1:]
    )

    plotting_utils.plot_coastlines(
        basemap_object=basemap_object, axes_object=axes_object,
        line_colour=plotting_utils.DEFAULT_COUNTRY_COLOUR)

    plotting_utils.plot_countries(
        basemap_object=basemap_object, axes_object=axes_object)

    plotting_utils.plot_states_and_provinces(
        basemap_object=basemap_object, axes_object=axes_object)

    plotting_utils.plot_parallels(
        basemap_object=basemap_object, axes_object=axes_object,
        num_parallels=NUM_PARALLELS, line_width=0)

    plotting_utils.plot_meridians(
        basemap_object=basemap_object, axes_object=axes_object,
        num_meridians=NUM_MERIDIANS, line_width=0)

    radar_plotting.plot_latlng_grid(
        field_matrix=radar_matrix, field_name=radar_field_name,
        axes_object=axes_object,
        min_grid_point_latitude_deg=numpy.min(grid_point_latitudes_deg),
        min_grid_point_longitude_deg=numpy.min(grid_point_longitudes_deg),
        latitude_spacing_deg=numpy.diff(grid_point_latitudes_deg[:2])[0],
        longitude_spacing_deg=numpy.diff(grid_point_longitudes_deg[:2])[0]
    )

    colour_map_object, colour_norm_object = (
        radar_plotting.get_default_colour_scheme(radar_field_name)
    )

    plotting_utils.plot_colour_bar(
        axes_object_or_matrix=axes_object, data_matrix=radar_matrix,
        colour_map_object=colour_map_object,
        colour_norm_object=colour_norm_object, orientation_string='horizontal',
        padding=0.05, extend_min=False, extend_max=True,
        fraction_of_axis_length=0.8)

    first_list, second_list = temporal_tracking.full_to_partial_ids(
        [full_id_string]
    )
    primary_id_string = first_list[0]
    secondary_id_string = second_list[0]

    # Plot outlines of unrelated storms (with different primary IDs).
    this_storm_object_table = storm_object_table.loc[
        storm_object_table[tracking_utils.PRIMARY_ID_COLUMN] !=
        primary_id_string
    ]

    storm_plotting.plot_storm_outlines(
        storm_object_table=this_storm_object_table, axes_object=axes_object,
        basemap_object=basemap_object, line_width=AUXILIARY_STORM_WIDTH,
        line_colour='k', line_style='dashed')

    # Plot outlines of related storms (with the same primary ID).
    this_storm_object_table = storm_object_table.loc[
        (storm_object_table[tracking_utils.PRIMARY_ID_COLUMN] ==
         primary_id_string) &
        (storm_object_table[tracking_utils.SECONDARY_ID_COLUMN] !=
         secondary_id_string)
    ]

    this_num_storm_objects = len(this_storm_object_table.index)

    if this_num_storm_objects > 0:
        storm_plotting.plot_storm_outlines(
            storm_object_table=this_storm_object_table, axes_object=axes_object,
            basemap_object=basemap_object, line_width=AUXILIARY_STORM_WIDTH,
            line_colour='k', line_style='solid'
        )

        for j in range(len(this_storm_object_table)):
            axes_object.text(
                this_storm_object_table[
                    tracking_utils.CENTROID_LONGITUDE_COLUMN
                ].values[j],
                this_storm_object_table[
                    tracking_utils.CENTROID_LATITUDE_COLUMN
                ].values[j],
                'P',
                fontsize=MAIN_FONT_SIZE, color=FONT_COLOUR, fontweight='bold',
                horizontalalignment='center', verticalalignment='center'
            )

    # Plot outline of storm of interest (same secondary ID).
    this_storm_object_table = storm_object_table.loc[
        storm_object_table[tracking_utils.SECONDARY_ID_COLUMN] ==
        secondary_id_string
    ]

    storm_plotting.plot_storm_outlines(
        storm_object_table=this_storm_object_table, axes_object=axes_object,
        basemap_object=basemap_object, line_width=MAIN_STORM_WIDTH,
        line_colour='k', line_style='solid')

    this_num_storm_objects = len(this_storm_object_table.index)

    plot_forecast = (
        this_num_storm_objects > 0 and
        FORECAST_PROBABILITY_COLUMN in list(this_storm_object_table)
    )

    if plot_forecast:
        label_string = 'Prob = {0:.3f}\nat {1:s}'.format(
            this_storm_object_table[FORECAST_PROBABILITY_COLUMN].values[0],
            time_conversion.unix_sec_to_string(
                valid_time_unix_sec, TORNADO_TIME_FORMAT)
        )

        axes_object.set_title(
            label_string.replace('\n', ' '), fontsize=TITLE_FONT_SIZE
        )

    tornado_id_strings = tornado_table[tornado_io.TORNADO_ID_COLUMN].values

    for this_tornado_id_string in numpy.unique(tornado_id_strings):
        these_rows = numpy.where(
            tornado_id_strings == this_tornado_id_string
        )[0]

        this_tornado_table = tornado_table.iloc[these_rows].sort_values(
            linkage.EVENT_TIME_COLUMN, axis=0, ascending=True, inplace=False
        )
        _plot_one_tornado(
            tornado_table=this_tornado_table, axes_object=axes_object
        )
コード例 #7
0
def _plot_echo_tops(echo_top_matrix_km_asl, latitudes_deg, longitudes_deg,
                    plot_colour_bar, convective_flag_matrix=None):
    """Plots grid of 40-dBZ echo tops.

    M = number of rows in grid
    N = number of columns in grid

    :param echo_top_matrix_km_asl: M-by-N numpy array of echo tops (km above sea
        level).
    :param latitudes_deg: length-M numpy array of latitudes (deg N).
    :param longitudes_deg: length-N numpy array of longitudes (deg E).
    :param plot_colour_bar: Boolean flag.
    :param convective_flag_matrix: M-by-N numpy array of Boolean flags,
        indicating which grid cells are convective.  If
        `convective_flag_matrix is None`, all grid cells will be plotted.  If
        `convective_flag_matrix is not None`, only convective grid cells will be
        plotted.
    :return: figure_object: Figure handle (instance of
        `matplotlib.figure.Figure`).
    :return: axes_object: Axes handle (instance of
        `matplotlib.axes._subplots.AxesSubplot`).
    :return: basemap_object: Basemap handle (instance of
        `mpl_toolkits.basemap.Basemap`).
    """

    figure_object, axes_object, basemap_object = (
        plotting_utils.create_equidist_cylindrical_map(
            min_latitude_deg=numpy.min(latitudes_deg),
            max_latitude_deg=numpy.max(latitudes_deg),
            min_longitude_deg=numpy.min(longitudes_deg),
            max_longitude_deg=numpy.max(longitudes_deg), resolution_string='h'
        )
    )

    # plotting_utils.plot_coastlines(
    #     basemap_object=basemap_object, axes_object=axes_object,
    #     line_colour=plotting_utils.DEFAULT_COUNTRY_COLOUR
    # )
    plotting_utils.plot_countries(
        basemap_object=basemap_object, axes_object=axes_object
    )
    plotting_utils.plot_states_and_provinces(
        basemap_object=basemap_object, axes_object=axes_object
    )
    plotting_utils.plot_parallels(
        basemap_object=basemap_object, axes_object=axes_object,
        num_parallels=NUM_PARALLELS, line_width=0
    )
    plotting_utils.plot_meridians(
        basemap_object=basemap_object, axes_object=axes_object,
        num_meridians=NUM_MERIDIANS, line_width=0
    )

    matrix_to_plot = echo_top_matrix_km_asl + 0.
    if convective_flag_matrix is not None:
        matrix_to_plot[convective_flag_matrix == False] = numpy.nan

    radar_plotting.plot_latlng_grid(
        field_matrix=matrix_to_plot, field_name=radar_utils.ECHO_TOP_40DBZ_NAME,
        axes_object=axes_object,
        min_grid_point_latitude_deg=numpy.min(latitudes_deg),
        min_grid_point_longitude_deg=numpy.min(longitudes_deg),
        latitude_spacing_deg=numpy.diff(latitudes_deg[:2])[0],
        longitude_spacing_deg=numpy.diff(longitudes_deg[:2])[0]
    )

    if not plot_colour_bar:
        return figure_object, axes_object, basemap_object

    colour_map_object, colour_norm_object = (
        radar_plotting.get_default_colour_scheme(
            radar_utils.ECHO_TOP_40DBZ_NAME)
    )

    colour_bar_object = plotting_utils.plot_colour_bar(
        axes_object_or_matrix=axes_object, data_matrix=matrix_to_plot,
        colour_map_object=colour_map_object,
        colour_norm_object=colour_norm_object, orientation_string='horizontal',
        extend_min=False, extend_max=True, fraction_of_axis_length=1.
    )

    colour_bar_object.set_label('40-dBZ echo top (kft ASL)')

    return figure_object, axes_object, basemap_object