Exemple #1
0
def _plot_start_or_end_markers(
        storm_object_table_one_track, axes_object, plot_at_start, marker_type,
        marker_size, track_colour=None, colour_map_object=None,
        colour_norm_object=None):
    """Plots marker at beginning or end of each storm track.

    :param storm_object_table_one_track: Same as input for `plot_storm_tracks`,
        except that this table contains only one track (primary storm ID).
    :param axes_object: See doc for `plot_storm_outlines`.
    :param plot_at_start: Boolean flag.  If True, will plot at beginning of each
        track.  If False, at end of each track.
    :param marker_type: Marker type.
    :param marker_size: Marker size.
    :param track_colour: Track colour.  This may be None.
    :param colour_map_object: [used only if `track_colour is None`]:
        Colour scheme (instance of `matplotlib.pyplot.cm` or similar).
    :param colour_norm_object: Normalizer for colour scheme.
    """

    num_storm_objects = len(storm_object_table_one_track.index)

    for i in range(num_storm_objects):
        if plot_at_start:
            these_indices = temporal_tracking.find_immediate_predecessors(
                storm_object_table=storm_object_table_one_track, target_row=i
            )
        else:
            these_indices = temporal_tracking.find_immediate_successors(
                storm_object_table=storm_object_table_one_track, target_row=i
            )

        if len(these_indices) > 0:
            continue

        if colour_map_object is None:
            this_colour = track_colour
        else:
            this_time_unix_sec = storm_object_table_one_track[
                tracking_utils.VALID_TIME_COLUMN
            ].values[i]

            this_colour = colour_map_object(colour_norm_object(
                this_time_unix_sec
            ))

        this_x_coord = storm_object_table_one_track[
            tracking_utils.CENTROID_X_COLUMN
        ].values[i]

        this_y_coord = storm_object_table_one_track[
            tracking_utils.CENTROID_Y_COLUMN
        ].values[i]

        axes_object.plot(
            this_x_coord, this_y_coord, linestyle='None',
            marker=marker_type, markersize=marker_size,
            markerfacecolor=this_colour, markeredgecolor=this_colour,
            markeredgewidth=2 if marker_type == 'x' else 1
        )
    def test_find_immediate_successors_first_5sec(self):
        """Ensures correct output from find_immediate_successors.

        In this case, working on the first table with max time difference =
        5 seconds.
        """

        this_num_storm_objects = len(FIRST_STORM_OBJECT_TABLE.index)

        for i in range(this_num_storm_objects):
            these_successor_rows = temporal_tracking.find_immediate_successors(
                storm_object_table=FIRST_STORM_OBJECT_TABLE,
                target_row=i,
                max_time_diff_seconds=5)

            these_successor_rows = numpy.sort(these_successor_rows)
            these_expected_rows = numpy.sort(
                numpy.array(FIRST_IMMED_SUCCESSOR_DICT_5SEC[i], dtype=int))

            self.assertTrue(
                numpy.array_equal(these_successor_rows, these_expected_rows))
Exemple #3
0
def _plot_one_track(
        storm_object_table_one_track, axes_object, basemap_object, line_width,
        line_colour=None, colour_map_object=None, colour_norm_object=None):
    """Plots one storm track.

    :param storm_object_table_one_track: Same as input for `plot_storm_tracks`,
        except that this table contains only one track (primary storm ID).
    :param axes_object: See doc for `plot_storm_outlines`.
    :param basemap_object: Same.
    :param line_width: Track width.
    :param line_colour: Track colour.  This may be None.
    :param colour_map_object: [used only if `line_colour is None`]:
        Colour scheme (instance of `matplotlib.pyplot.cm` or similar).
    :param colour_norm_object: Normalizer for colour scheme.
    """

    num_storm_objects = len(storm_object_table_one_track.index)

    if num_storm_objects == 1:
        this_storm_object_table = storm_object_table_one_track.iloc[[0, 0]]

        _plot_one_track_segment(
            storm_object_table_one_segment=this_storm_object_table,
            axes_object=axes_object, basemap_object=basemap_object,
            line_width=line_width, line_colour=line_colour,
            colour_map_object=colour_map_object,
            colour_norm_object=colour_norm_object)

        return

    latitudes_deg = 0. + storm_object_table_one_track[
        tracking_utils.CENTROID_LATITUDE_COLUMN
    ].values[[0, -1]]

    longitudes_deg = 0. + storm_object_table_one_track[
        tracking_utils.CENTROID_LONGITUDE_COLUMN
    ].values[[0, -1]]

    x_coords = _lengthen_segment(
        latitudes_deg=latitudes_deg, longitudes_deg=longitudes_deg,
        basemap_object=basemap_object
    )[0]
    x_coords = None

    if x_coords is not None:
        this_storm_object_table = storm_object_table_one_track.iloc[[0, -1]]

        _plot_one_track_segment(
            storm_object_table_one_segment=this_storm_object_table,
            axes_object=axes_object, basemap_object=basemap_object,
            line_width=line_width, line_colour=line_colour,
            colour_map_object=colour_map_object,
            colour_norm_object=colour_norm_object)

        return

    for i in range(num_storm_objects):
        successor_rows = temporal_tracking.find_immediate_successors(
            storm_object_table=storm_object_table_one_track, target_row=i
        )

        for j in successor_rows:
            this_storm_object_table = storm_object_table_one_track.iloc[[i, j]]

            _plot_one_track_segment(
                storm_object_table_one_segment=this_storm_object_table,
                axes_object=axes_object, basemap_object=basemap_object,
                line_width=line_width, line_colour=line_colour,
                colour_map_object=colour_map_object,
                colour_norm_object=colour_norm_object)
Exemple #4
0
def plot_storm_tracks(storm_object_table,
                      axes_object,
                      basemap_object,
                      colour_map_object='random',
                      line_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 one or more storm tracks on the same map.

    :param storm_object_table: See doc for `plot_storm_outlines`.
    :param axes_object: Same.
    :param basemap_object: Same.
    :param colour_map_object: There are 3 cases.

    If "random", each track will be plotted in a random colour from
    `get_storm_track_colours`.

    If None, each track will be plotted in `line_colour` (the next input arg).

    If real colour map (instance of `matplotlib.pyplot.cm`), track segments will
    be coloured by time, according to this colour map.

    :param line_colour: [used only if `colour_map_object is None`]
        length-3 numpy array with (R, G, B).  Will be used for all tracks.
    :param line_width: Width of each storm track.
    :param start_marker_type: Marker type for beginning of track (in any format
        accepted by `matplotlib.lines`).  If `start_marker_type is None`,
        markers will not be used to show beginning of each track.
    :param end_marker_type: Same but for end of track.
    :param start_marker_size: Size of each start-point marker.
    :param end_marker_size: Size of each end-point marker.
    """

    plot_start_markers = start_marker_type is not None
    plot_end_markers = end_marker_type is not None

    if start_marker_type is None:
        start_marker_type = DEFAULT_START_MARKER_TYPE
        start_marker_size = DEFAULT_START_MARKER_SIZE

    if end_marker_type is None:
        end_marker_type = DEFAULT_END_MARKER_TYPE
        end_marker_size = DEFAULT_END_MARKER_SIZE

    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 = None
    num_colours = None
    colour_norm_object = None

    if colour_map_object is None:
        error_checking.assert_is_numpy_array(line_colour,
                                             exact_dimensions=numpy.array(
                                                 [3], dtype=int))

        rgb_matrix = numpy.reshape(line_colour, (1, 3))
        num_colours = rgb_matrix.shape[0]

    elif colour_map_object == 'random':
        rgb_matrix = get_storm_track_colours()
        num_colours = rgb_matrix.shape[0]

        colour_map_object = None

    else:
        first_time_unix_sec = numpy.min(
            storm_object_table[tracking_utils.VALID_TIME_COLUMN].values)
        last_time_unix_sec = numpy.max(
            storm_object_table[tracking_utils.VALID_TIME_COLUMN].values)

        colour_norm_object = pyplot.Normalize(first_time_unix_sec,
                                              last_time_unix_sec)

    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 k in range(num_tracks):
        if colour_map_object is None:
            this_colour = rgb_matrix[numpy.mod(k, 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 == k)[0]

        for i in these_object_indices:
            these_next_indices = temporal_tracking.find_immediate_successors(
                storm_object_table=storm_object_table, target_row=i)

            # if len(these_next_indices) > 1:
            #     axes_object.text(
            #         storm_object_table[
            #             tracking_utils.CENTROID_X_COLUMN].values[i],
            #         storm_object_table[
            #             tracking_utils.CENTROID_Y_COLUMN].values[i],
            #         '{0:d}-WAY SPLIT'.format(len(these_next_indices)),
            #         fontsize=12, color='k',
            #         horizontalalignment='left', verticalalignment='top')

            for j in these_next_indices:
                these_x_coords_metres = storm_object_table[
                    tracking_utils.CENTROID_X_COLUMN].values[[i, j]]

                these_y_coords_metres = storm_object_table[
                    tracking_utils.CENTROID_Y_COLUMN].values[[i, j]]

                if colour_map_object is None:
                    axes_object.plot(these_x_coords_metres,
                                     these_y_coords_metres,
                                     color=this_colour,
                                     linestyle='solid',
                                     linewidth=line_width)
                else:
                    this_point_matrix = numpy.array(
                        [these_x_coords_metres,
                         these_y_coords_metres]).T.reshape(-1, 1, 2)

                    this_segment_matrix = numpy.concatenate(
                        [this_point_matrix[:-1], this_point_matrix[1:]],
                        axis=1)

                    this_time_unix_sec = numpy.mean(storm_object_table[
                        tracking_utils.VALID_TIME_COLUMN].values[[i, j]])

                    this_line_collection_object = LineCollection(
                        this_segment_matrix,
                        cmap=colour_map_object,
                        norm=colour_norm_object)

                    this_line_collection_object.set_array(
                        numpy.array([this_time_unix_sec]))
                    this_line_collection_object.set_linewidth(line_width)
                    axes_object.add_collection(this_line_collection_object)

            these_prev_indices = temporal_tracking.find_immediate_predecessors(
                storm_object_table=storm_object_table, target_row=i)

            # if len(these_prev_indices) > 1:
            #     axes_object.text(
            #         storm_object_table[
            #             tracking_utils.CENTROID_X_COLUMN].values[i],
            #         storm_object_table[
            #             tracking_utils.CENTROID_Y_COLUMN].values[i],
            #         '{0:d}-WAY MERGER'.format(len(these_prev_indices)),
            #         fontsize=12, color='k',
            #         horizontalalignment='left', verticalalignment='top')

            plot_this_start_marker = ((plot_start_markers
                                       and len(these_prev_indices) == 0)
                                      or len(these_object_indices) == 1)

            if plot_this_start_marker:
                if colour_map_object is not None:
                    this_colour = colour_map_object(
                        colour_norm_object(storm_object_table[
                            tracking_utils.VALID_TIME_COLUMN].values[i]))

                if start_marker_type == 'x':
                    this_edge_width = 2
                else:
                    this_edge_width = 1

                axes_object.plot(
                    storm_object_table[
                        tracking_utils.CENTROID_X_COLUMN].values[i],
                    storm_object_table[
                        tracking_utils.CENTROID_Y_COLUMN].values[i],
                    linestyle='None',
                    marker=start_marker_type,
                    markerfacecolor=this_colour,
                    markeredgecolor=this_colour,
                    markersize=start_marker_size,
                    markeredgewidth=this_edge_width)

            plot_this_end_marker = ((plot_end_markers
                                     and len(these_next_indices) == 0)
                                    or len(these_object_indices) == 1)

            if plot_this_end_marker:
                if colour_map_object is not None:
                    this_colour = colour_map_object(
                        colour_norm_object(storm_object_table[
                            tracking_utils.VALID_TIME_COLUMN].values[i]))

                if end_marker_type == 'x':
                    this_edge_width = 2
                else:
                    this_edge_width = 1

                axes_object.plot(
                    storm_object_table[
                        tracking_utils.CENTROID_X_COLUMN].values[i],
                    storm_object_table[
                        tracking_utils.CENTROID_Y_COLUMN].values[i],
                    linestyle='None',
                    marker=end_marker_type,
                    markerfacecolor=this_colour,
                    markeredgecolor=this_colour,
                    markersize=end_marker_size,
                    markeredgewidth=this_edge_width)

    if colour_map_object is None:
        return

    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

    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_linear_colour_bar(
        axes_object_or_matrix=axes_object,
        data_matrix=storm_object_table[
            tracking_utils.VALID_TIME_COLUMN].values,
        colour_map_object=colour_map_object,
        min_value=colour_norm_object.vmin,
        max_value=colour_norm_object.vmax,
        orientation_string=orientation_string,
        extend_min=False,
        extend_max=False,
        fraction_of_axis_length=0.9,
        font_size=COLOUR_BAR_FONT_SIZE)

    if orientation_string == 'horizontal':
        tick_values = colour_bar_object.ax.get_xticks()
    else:
        tick_values = colour_bar_object.ax.get_yticks()

    tick_times_unix_sec = numpy.round(
        colour_norm_object.inverse(tick_values)).astype(int)

    slope_sec_per_sec = (float(last_time_unix_sec - first_time_unix_sec) /
                         (tick_times_unix_sec[-1] - tick_times_unix_sec[0]))

    tick_times_unix_sec = numpy.round(
        first_time_unix_sec + slope_sec_per_sec *
        (tick_times_unix_sec - tick_times_unix_sec[0])).astype(int)

    tick_time_strings = [
        time_conversion.unix_sec_to_string(t, '%Y-%m-%d-%H%M%S')
        for t in tick_times_unix_sec
    ]

    print(tick_time_strings)

    tick_time_strings = [
        time_conversion.unix_sec_to_string(t, COLOUR_BAR_TIME_FORMAT)
        for t in tick_times_unix_sec
    ]

    print(tick_time_strings)

    colour_bar_object.set_ticks(tick_values)
    colour_bar_object.set_ticklabels(tick_time_strings)