Пример #1
0
def project_xy_to_latlng(polygon_object_xy_metres,
                         projection_object,
                         false_easting_metres=0,
                         false_northing_metres=0.):
    """Converts polygon from x-y to lat-long coordinates.

    :param polygon_object_xy_metres: `shapely.geometry.Polygon` object with
        vertices in x-y coordinates.
    :param projection_object: `pyproj.Proj` object.  Will be used to convert
        coordinates.
    :param false_easting_metres: False easting (will be subtracted from all x-
        coordinates before converting).
    :param false_northing_metres: False northing (will be subtracted from all y-
        coordinates before converting).
    :return: polygon_object_latlng: `shapely.geometry.Polygon` object with
        vertices in lat-long coordinates.
    """

    vertex_dict = polygon_object_to_vertex_arrays(polygon_object_xy_metres)
    vertex_dict[EXTERIOR_Y_COLUMN], vertex_dict[EXTERIOR_X_COLUMN] = (
        projections.project_xy_to_latlng(
            vertex_dict[EXTERIOR_X_COLUMN],
            vertex_dict[EXTERIOR_Y_COLUMN],
            projection_object=projection_object,
            false_easting_metres=false_easting_metres,
            false_northing_metres=false_northing_metres))

    num_holes = len(vertex_dict[HOLE_X_COLUMN])
    for i in range(num_holes):
        vertex_dict[HOLE_Y_COLUMN][i], vertex_dict[HOLE_X_COLUMN][i] = (
            projections.project_xy_to_latlng(
                vertex_dict[HOLE_X_COLUMN][i],
                vertex_dict[HOLE_Y_COLUMN][i],
                projection_object=projection_object,
                false_easting_metres=false_easting_metres,
                false_northing_metres=false_northing_metres))

    if num_holes == 0:
        polygon_object_latlng = vertex_arrays_to_polygon_object(
            vertex_dict[EXTERIOR_X_COLUMN], vertex_dict[EXTERIOR_Y_COLUMN])
    else:
        polygon_object_latlng = vertex_arrays_to_polygon_object(
            vertex_dict[EXTERIOR_X_COLUMN],
            vertex_dict[EXTERIOR_Y_COLUMN],
            hole_x_coords_list=vertex_dict[HOLE_X_COLUMN],
            hole_y_coords_list=vertex_dict[HOLE_Y_COLUMN])

    return polygon_object_latlng
Пример #2
0
def project_xy_to_latlng(x_coords_metres,
                         y_coords_metres,
                         projection_object=None,
                         model_name=None,
                         grid_id=None):
    """Converts from x-y coordinates (under model projection) to lat-long.

    P = number of points to convert

    :param x_coords_metres: length-P numpy array of x-coordinates.
    :param y_coords_metres: length-P numpy array of y-coordinates.
    Projection object created by
        init_model_projection.  If projection_object = None, it will be created
        on the fly, based on args `model_name` and `grid_id`.
    :param model_name: Name of model.
    :param grid_id: ID for model grid.
    :return: latitudes_deg: length-P numpy array of latitudes (deg N).
    :return: longitudes_deg: length-P numpy array of longitudes (deg E).
    """

    false_easting_metres, false_northing_metres = (
        get_false_easting_and_northing(model_name, grid_id))
    if projection_object is None:
        projection_object = init_model_projection(model_name)

    return projections.project_xy_to_latlng(
        x_coords_metres,
        y_coords_metres,
        projection_object=projection_object,
        false_easting_metres=false_easting_metres,
        false_northing_metres=false_northing_metres)
Пример #3
0
    def test_project_xy_to_latlng(self):
        """Ensures that project_xy_to_latlng does not crash.

        This is an integration test, not a unit test, because it requires
        init_lambert_conformal_projection to create the projection object.
        """

        projection_object = projections.init_lambert_conformal_projection(
            STANDARD_LATITUDES_DEG, CENTRAL_LONGITUDE_DEG)

        projections.project_xy_to_latlng(
            X_COORDS_METRES,
            Y_COORDS_METRES,
            projection_object=projection_object,
            false_easting_metres=FALSE_EASTING_METRES,
            false_northing_metres=FALSE_NORTHING_METRES)
def project_xy_to_latlng(x_coords_metres,
                         y_coords_metres,
                         projection_object=None,
                         model_name=None,
                         grid_name=None):
    """Converts points from x-y (model) to lat-long coordinates.

    P = number of points

    :param x_coords_metres: length-P numpy array of x-coordinates.
    :param y_coords_metres: length-P numpy array of x-coordinates.
    :param projection_object: Instance of `pyproj.Proj`, specifying the
        projection.  If None, will create projection object on the fly.
    :param model_name: See doc for `check_grid_name`.
    :param grid_name: Same.
    :return: latitudes_deg: length-P numpy array of latitudes (deg N).
    :return: longitudes_deg: length-P numpy array of longitudes (deg E).
    """

    false_easting_metres, false_northing_metres = (
        get_false_easting_and_northing(model_name=model_name,
                                       grid_name=grid_name))

    if projection_object is None:
        projection_object = init_projection(model_name)

    return projections.project_xy_to_latlng(
        x_coords_metres=x_coords_metres,
        y_coords_metres=y_coords_metres,
        projection_object=projection_object,
        false_easting_metres=false_easting_metres,
        false_northing_metres=false_northing_metres)
Пример #5
0
    def test_project_xy_to_latlng(self):
        """Ensures that project_xy_to_latlng does not crash.

        This is an integration test, not a unit test, because it requires
        init_lcc_projection to create the projection object.
        """

        projection_object = projections.init_lcc_projection(
            standard_latitudes_deg=STANDARD_LATITUDES_DEG,
            central_longitude_deg=CENTRAL_LONGITUDE_DEG)

        projections.project_xy_to_latlng(
            x_coords_metres=X_COORDS_METRES,
            y_coords_metres=Y_COORDS_METRES,
            projection_object=projection_object,
            false_easting_metres=FALSE_EASTING_METRES,
            false_northing_metres=FALSE_NORTHING_METRES)
Пример #6
0
def _get_basemap(grid_metadata_dict):
    """Creates basemap.

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

    :param grid_metadata_dict: Dictionary returned by
        `grids.read_equidistant_metafile`.
    :return: basemap_object: Basemap handle (instance of
        `mpl_toolkits.basemap.Basemap`).
    :return: basemap_x_matrix_metres: M-by-N numpy array of x-coordinates under
        Basemap projection (different than pyproj projection).
    :return: basemap_y_matrix_metres: Same but for y-coordinates.
    """

    x_matrix_metres, y_matrix_metres = grids.xy_vectors_to_matrices(
        x_unique_metres=grid_metadata_dict[grids.X_COORDS_KEY],
        y_unique_metres=grid_metadata_dict[grids.Y_COORDS_KEY])

    projection_object = grid_metadata_dict[grids.PROJECTION_KEY]

    latitude_matrix_deg, longitude_matrix_deg = (
        projections.project_xy_to_latlng(x_coords_metres=x_matrix_metres,
                                         y_coords_metres=y_matrix_metres,
                                         projection_object=projection_object))

    standard_latitudes_deg, central_longitude_deg = _get_lcc_params(
        projection_object)

    basemap_object = Basemap(projection='lcc',
                             lat_1=standard_latitudes_deg[0],
                             lat_2=standard_latitudes_deg[1],
                             lon_0=central_longitude_deg,
                             rsphere=projections.DEFAULT_EARTH_RADIUS_METRES,
                             ellps=projections.SPHERE_NAME,
                             resolution=RESOLUTION_STRING,
                             llcrnrx=x_matrix_metres[0, 0],
                             llcrnry=y_matrix_metres[0, 0],
                             urcrnrx=x_matrix_metres[-1, -1],
                             urcrnry=y_matrix_metres[-1, -1])

    basemap_x_matrix_metres, basemap_y_matrix_metres = basemap_object(
        longitude_matrix_deg, latitude_matrix_deg)

    return basemap_object, basemap_x_matrix_metres, basemap_y_matrix_metres
Пример #7
0
    def test_project_both_ways(self):
        """Ensures that the two projection methods are inverses.

        This is an integration test, not a unit test, because it calls both
        projection methods.  Also, it requires init_lcc_projection
        to create the projection object.
        """

        projection_object = projections.init_lcc_projection(
            standard_latitudes_deg=STANDARD_LATITUDES_DEG,
            central_longitude_deg=CENTRAL_LONGITUDE_DEG)

        these_x_coords_metres, these_y_coords_metres = (
            projections.project_latlng_to_xy(
                latitudes_deg=LATITUDES_DEG,
                longitudes_deg=LONGITUDES_DEG,
                projection_object=projection_object,
                false_easting_metres=FALSE_EASTING_METRES,
                false_northing_metres=FALSE_NORTHING_METRES))

        these_latitudes_deg, these_longitudes_deg = (
            projections.project_xy_to_latlng(
                x_coords_metres=these_x_coords_metres,
                y_coords_metres=these_y_coords_metres,
                projection_object=projection_object,
                false_easting_metres=FALSE_EASTING_METRES,
                false_northing_metres=FALSE_NORTHING_METRES))

        self.assertTrue(
            numpy.allclose(these_latitudes_deg,
                           LATITUDES_DEG,
                           atol=TOLERANCE,
                           equal_nan=True))
        self.assertTrue(
            numpy.allclose(these_longitudes_deg,
                           LONGITUDES_DEG,
                           atol=TOLERANCE,
                           equal_nan=True))
def create_distance_buffers(storm_object_table, min_distances_metres,
                            max_distances_metres):
    """Creates one or more distance buffers around each storm object.

    K = number of buffers

    :param storm_object_table: pandas DataFrame with the following columns.
        Each row is one storm object.
    storm_object_table.centroid_latitude_deg: Latitude (deg N) of storm-object
        centroid.
    storm_object_table.centroid_longitude_deg: Longitude (deg E) of storm-object
        centroid.
    storm_object_table.polygon_object_latlng_deg: Instance of
        `shapely.geometry.Polygon`, with x-coords in longitude (deg E) and
        y-coords in latitude (deg N).

    :param min_distances_metres: length-K numpy array of minimum distances.  If
        the storm object is inside the [k]th buffer -- i.e., the [k]th buffer
        has no minimum distance -- then min_distances_metres[k] should be NaN.
    :param max_distances_metres: length-K numpy array of max distances.
    :return: storm_object_table: Same as input but with K additional columns
        (one per distance buffer).  Column names are generated by
        `buffer_to_column_name`, and each value in these columns is a
        `shapely.geometry.Polygon` object, with x-coords in longitude (deg E) and
        y-coords in latitude (deg N).
    """

    num_buffers = len(min_distances_metres)
    these_expected_dim = numpy.array([num_buffers], dtype=int)
    error_checking.assert_is_numpy_array(max_distances_metres,
                                         exact_dimensions=these_expected_dim)

    global_centroid_lat_deg, global_centroid_lng_deg = (
        geodetic_utils.get_latlng_centroid(
            latitudes_deg=storm_object_table[CENTROID_LATITUDE_COLUMN].values,
            longitudes_deg=storm_object_table[CENTROID_LONGITUDE_COLUMN].values
        ))

    projection_object = projections.init_azimuthal_equidistant_projection(
        central_latitude_deg=global_centroid_lat_deg,
        central_longitude_deg=global_centroid_lng_deg)

    num_storm_objects = len(storm_object_table.index)
    object_array = numpy.full(num_storm_objects, numpy.nan, dtype=object)
    buffer_column_names = [''] * num_buffers

    for j in range(num_buffers):
        buffer_column_names[j] = buffer_to_column_name(
            min_distance_metres=min_distances_metres[j],
            max_distance_metres=max_distances_metres[j])

        storm_object_table = storm_object_table.assign(
            **{buffer_column_names[j]: object_array})

    for i in range(num_storm_objects):
        this_orig_vertex_dict_latlng_deg = (
            polygons.polygon_object_to_vertex_arrays(
                storm_object_table[LATLNG_POLYGON_COLUMN].values[i]))

        these_orig_x_metres, these_orig_y_metres = (
            projections.project_latlng_to_xy(
                latitudes_deg=this_orig_vertex_dict_latlng_deg[
                    polygons.EXTERIOR_Y_COLUMN],
                longitudes_deg=this_orig_vertex_dict_latlng_deg[
                    polygons.EXTERIOR_X_COLUMN],
                projection_object=projection_object))

        for j in range(num_buffers):
            this_buffer_poly_object_xy_metres = polygons.buffer_simple_polygon(
                vertex_x_metres=these_orig_x_metres,
                vertex_y_metres=these_orig_y_metres,
                min_buffer_dist_metres=min_distances_metres[j],
                max_buffer_dist_metres=max_distances_metres[j])

            this_buffer_vertex_dict = polygons.polygon_object_to_vertex_arrays(
                this_buffer_poly_object_xy_metres)

            (this_buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
             this_buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN]
             ) = projections.project_xy_to_latlng(
                 x_coords_metres=this_buffer_vertex_dict[
                     polygons.EXTERIOR_X_COLUMN],
                 y_coords_metres=this_buffer_vertex_dict[
                     polygons.EXTERIOR_Y_COLUMN],
                 projection_object=projection_object)

            this_num_holes = len(
                this_buffer_vertex_dict[polygons.HOLE_X_COLUMN])

            for k in range(this_num_holes):
                (this_buffer_vertex_dict[polygons.HOLE_Y_COLUMN][k],
                 this_buffer_vertex_dict[polygons.HOLE_X_COLUMN][k]
                 ) = projections.project_xy_to_latlng(
                     x_coords_metres=this_buffer_vertex_dict[
                         polygons.HOLE_X_COLUMN][k],
                     y_coords_metres=this_buffer_vertex_dict[
                         polygons.HOLE_Y_COLUMN][k],
                     projection_object=projection_object)

            this_buffer_poly_object_latlng_deg = (
                polygons.vertex_arrays_to_polygon_object(
                    exterior_x_coords=this_buffer_vertex_dict[
                        polygons.EXTERIOR_X_COLUMN],
                    exterior_y_coords=this_buffer_vertex_dict[
                        polygons.EXTERIOR_Y_COLUMN],
                    hole_x_coords_list=this_buffer_vertex_dict[
                        polygons.HOLE_X_COLUMN],
                    hole_y_coords_list=this_buffer_vertex_dict[
                        polygons.HOLE_Y_COLUMN]))

            storm_object_table[buffer_column_names[j]].values[i] = (
                this_buffer_poly_object_latlng_deg)

    return storm_object_table
def _run(top_gridrad_dir_name, first_spc_date_string, last_spc_date_string,
         colour_map_name, grid_spacing_metres, output_file_name):
    """Plots GridRad domains.

    This is effectively the main method.

    :param top_gridrad_dir_name: See documentation at top of file.
    :param first_spc_date_string: Same.
    :param last_spc_date_string: Same.
    :param colour_map_name: Same.
    :param grid_spacing_metres: Same.
    :param output_file_name: Same.
    """

    colour_map_object = pyplot.get_cmap(colour_map_name)
    file_system_utils.mkdir_recursive_if_necessary(file_name=output_file_name)

    first_time_unix_sec = time_conversion.get_start_of_spc_date(
        first_spc_date_string)
    last_time_unix_sec = time_conversion.get_end_of_spc_date(
        last_spc_date_string)

    valid_times_unix_sec = time_periods.range_and_interval_to_list(
        start_time_unix_sec=first_time_unix_sec,
        end_time_unix_sec=last_time_unix_sec,
        time_interval_sec=TIME_INTERVAL_SEC,
        include_endpoint=True)

    valid_spc_date_strings = [
        time_conversion.time_to_spc_date_string(t)
        for t in valid_times_unix_sec
    ]

    domain_min_latitudes_deg = []
    domain_max_latitudes_deg = []
    domain_min_longitudes_deg = []
    domain_max_longitudes_deg = []

    prev_domain_limits_deg = numpy.full(4, numpy.nan)
    prev_spc_date_string = 'foo'
    num_times = len(valid_times_unix_sec)

    for i in range(num_times):
        this_gridrad_file_name = gridrad_io.find_file(
            unix_time_sec=valid_times_unix_sec[i],
            top_directory_name=top_gridrad_dir_name,
            raise_error_if_missing=False)

        if not os.path.isfile(this_gridrad_file_name):
            continue

        these_domain_limits_deg = _get_domain_one_file(this_gridrad_file_name)
        same_domain = (valid_spc_date_strings[i] == prev_spc_date_string
                       and numpy.allclose(these_domain_limits_deg,
                                          prev_domain_limits_deg, TOLERANCE))

        if same_domain:
            continue

        prev_domain_limits_deg = these_domain_limits_deg + 0.
        prev_spc_date_string = valid_spc_date_strings[i]

        domain_min_latitudes_deg.append(these_domain_limits_deg[0])
        domain_max_latitudes_deg.append(these_domain_limits_deg[1])
        domain_min_longitudes_deg.append(these_domain_limits_deg[2])
        domain_max_longitudes_deg.append(these_domain_limits_deg[3])

    print(SEPARATOR_STRING)

    domain_min_latitudes_deg = numpy.array(domain_min_latitudes_deg)
    domain_max_latitudes_deg = numpy.array(domain_max_latitudes_deg)
    domain_min_longitudes_deg = numpy.array(domain_min_longitudes_deg)
    domain_max_longitudes_deg = numpy.array(domain_max_longitudes_deg)
    num_domains = len(domain_min_latitudes_deg)

    grid_metadata_dict = grids.create_equidistant_grid(
        min_latitude_deg=OVERALL_MIN_LATITUDE_DEG,
        max_latitude_deg=OVERALL_MAX_LATITUDE_DEG,
        min_longitude_deg=OVERALL_MIN_LONGITUDE_DEG,
        max_longitude_deg=OVERALL_MAX_LONGITUDE_DEG,
        x_spacing_metres=grid_spacing_metres,
        y_spacing_metres=grid_spacing_metres,
        azimuthal=False)

    unique_x_coords_metres = grid_metadata_dict[grids.X_COORDS_KEY]
    unique_y_coords_metres = grid_metadata_dict[grids.Y_COORDS_KEY]
    projection_object = grid_metadata_dict[grids.PROJECTION_KEY]

    x_coord_matrix_metres, y_coord_matrix_metres = grids.xy_vectors_to_matrices(
        x_unique_metres=unique_x_coords_metres,
        y_unique_metres=unique_y_coords_metres)

    latitude_matrix_deg, longitude_matrix_deg = (
        projections.project_xy_to_latlng(x_coords_metres=x_coord_matrix_metres,
                                         y_coords_metres=y_coord_matrix_metres,
                                         projection_object=projection_object))

    num_grid_rows = latitude_matrix_deg.shape[0]
    num_grid_columns = latitude_matrix_deg.shape[1]
    num_days_matrix = numpy.full((num_grid_rows, num_grid_columns), 0)

    for i in range(num_domains):
        if numpy.mod(i, 10) == 0:
            print('Have found grid points in {0:d} of {1:d} domains...'.format(
                i, num_domains))

        this_lat_flag_matrix = numpy.logical_and(
            latitude_matrix_deg >= domain_min_latitudes_deg[i],
            latitude_matrix_deg <= domain_max_latitudes_deg[i])
        this_lng_flag_matrix = numpy.logical_and(
            longitude_matrix_deg >= domain_min_longitudes_deg[i],
            longitude_matrix_deg <= domain_max_longitudes_deg[i])

        num_days_matrix += numpy.logical_and(this_lat_flag_matrix,
                                             this_lng_flag_matrix).astype(int)

    print(SEPARATOR_STRING)

    figure_object, axes_object = _plot_data(
        num_days_matrix=num_days_matrix,
        grid_metadata_dict=grid_metadata_dict,
        colour_map_object=colour_map_object)

    plotting_utils.label_axes(axes_object=axes_object, label_string='(c)')

    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)
Пример #10
0
def make_buffers_around_polygons(storm_object_table,
                                 min_buffer_dists_metres=None,
                                 max_buffer_dists_metres=None):
    """Creates one or more buffers around each storm polygon.

    N = number of buffers
    V = number of vertices in a given polygon

    :param storm_object_table: pandas DataFrame with the following columns.
    storm_object_table.storm_id: String ID for storm cell.
    storm_object_table.polygon_object_latlng: Instance of
        `shapely.geometry.Polygon`, with vertices in lat-long coordinates.
    :param min_buffer_dists_metres: length-N numpy array of minimum buffer
        distances.  If min_buffer_dists_metres[i] is NaN, the [i]th buffer
        includes the original polygon.  If min_buffer_dists_metres[i] is
        defined, the [i]th buffer is a "nested" buffer, not including the
        original polygon.
    :param max_buffer_dists_metres: length-N numpy array of maximum buffer
        distances.  Must be all real numbers (no NaN).
    :return: storm_object_table: Same as input, but with N extra columns.
    storm_object_table.polygon_object_latlng_buffer_<D>m: Instance of
        `shapely.geometry.Polygon` for D-metre buffer around storm.
    storm_object_table.polygon_object_latlng_buffer_<d>_<D>m: Instance of
        `shapely.geometry.Polygon` for d-to-D-metre buffer around storm.
    """

    error_checking.assert_is_geq_numpy_array(min_buffer_dists_metres,
                                             0.,
                                             allow_nan=True)
    error_checking.assert_is_numpy_array(min_buffer_dists_metres,
                                         num_dimensions=1)

    num_buffers = len(min_buffer_dists_metres)
    error_checking.assert_is_geq_numpy_array(max_buffer_dists_metres,
                                             0.,
                                             allow_nan=False)
    error_checking.assert_is_numpy_array(max_buffer_dists_metres,
                                         exact_dimensions=numpy.array(
                                             [num_buffers]))

    for j in range(num_buffers):
        if numpy.isnan(min_buffer_dists_metres[j]):
            continue
        error_checking.assert_is_greater(max_buffer_dists_metres[j],
                                         min_buffer_dists_metres[j],
                                         allow_nan=False)

    num_storm_objects = len(storm_object_table.index)
    centroid_latitudes_deg = numpy.full(num_storm_objects, numpy.nan)
    centroid_longitudes_deg = numpy.full(num_storm_objects, numpy.nan)

    for i in range(num_storm_objects):
        this_centroid_object = storm_object_table[
            POLYGON_OBJECT_LATLNG_COLUMN].values[0].centroid
        centroid_latitudes_deg[i] = this_centroid_object.y
        centroid_longitudes_deg[i] = this_centroid_object.x

    global_centroid_lat_deg, global_centroid_lng_deg = (
        polygons.get_latlng_centroid(centroid_latitudes_deg,
                                     centroid_longitudes_deg))
    projection_object = projections.init_azimuthal_equidistant_projection(
        global_centroid_lat_deg, global_centroid_lng_deg)

    object_array = numpy.full(num_storm_objects, numpy.nan, dtype=object)
    argument_dict = {}
    buffer_column_names = [''] * num_buffers

    for j in range(num_buffers):
        buffer_column_names[j] = distance_buffer_to_column_name(
            min_buffer_dists_metres[j], max_buffer_dists_metres[j])
        argument_dict.update({buffer_column_names[j]: object_array})
    storm_object_table = storm_object_table.assign(**argument_dict)

    for i in range(num_storm_objects):
        orig_vertex_dict_latlng = polygons.polygon_object_to_vertex_arrays(
            storm_object_table[POLYGON_OBJECT_LATLNG_COLUMN].values[i])

        (orig_vertex_x_metres,
         orig_vertex_y_metres) = projections.project_latlng_to_xy(
             orig_vertex_dict_latlng[polygons.EXTERIOR_Y_COLUMN],
             orig_vertex_dict_latlng[polygons.EXTERIOR_X_COLUMN],
             projection_object=projection_object)

        for j in range(num_buffers):
            buffer_polygon_object_xy = polygons.buffer_simple_polygon(
                orig_vertex_x_metres,
                orig_vertex_y_metres,
                min_buffer_dist_metres=min_buffer_dists_metres[j],
                max_buffer_dist_metres=max_buffer_dists_metres[j])

            buffer_vertex_dict = polygons.polygon_object_to_vertex_arrays(
                buffer_polygon_object_xy)

            (buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
             buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN]) = (
                 projections.project_xy_to_latlng(
                     buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN],
                     buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
                     projection_object=projection_object))

            this_num_holes = len(buffer_vertex_dict[polygons.HOLE_X_COLUMN])
            for k in range(this_num_holes):
                (buffer_vertex_dict[polygons.HOLE_Y_COLUMN][k],
                 buffer_vertex_dict[polygons.HOLE_X_COLUMN][k]) = (
                     projections.project_xy_to_latlng(
                         buffer_vertex_dict[polygons.HOLE_X_COLUMN][k],
                         buffer_vertex_dict[polygons.HOLE_Y_COLUMN][k],
                         projection_object=projection_object))

            buffer_polygon_object_latlng = (
                polygons.vertex_arrays_to_polygon_object(
                    buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN],
                    buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
                    hole_x_coords_list=buffer_vertex_dict[
                        polygons.HOLE_X_COLUMN],
                    hole_y_coords_list=buffer_vertex_dict[
                        polygons.HOLE_Y_COLUMN]))

            storm_object_table[buffer_column_names[j]].values[
                i] = buffer_polygon_object_latlng

    return storm_object_table
def make_buffers_around_storm_objects(
        storm_object_table, min_distances_metres, max_distances_metres):
    """Creates one or more distance buffers around each storm object.

    N = number of storm objects
    B = number of buffers around each storm object
    V = number of vertices in a given buffer

    :param storm_object_table: N-row pandas DataFrame with the following
        columns.
    storm_object_table.storm_id: String ID for storm cell.
    storm_object_table.polygon_object_latlng: Instance of
        `shapely.geometry.Polygon`, containing vertices of storm object in
        lat-long coordinates.

    :param min_distances_metres: length-B numpy array of minimum buffer
        distances.  If min_distances_metres[i] is NaN, the storm object is
        included in the [i]th buffer, so the [i]th buffer is inclusive.  If
        min_distances_metres[i] is a real number, the storm object is *not*
        included in the [i]th buffer, so the [i]th buffer is exclusive.
    :param max_distances_metres: length-B numpy array of maximum buffer
        distances.  Must be all real numbers (no NaN).
    :return: storm_object_table: Same as input, but with B additional columns.
        Each additional column (listed below) contains a
        `shapely.geometry.Polygon` instance for each storm object.  Each
        `shapely.geometry.Polygon` instance contains the lat-long vertices of
        one distance buffer around one storm object.
    storm_object_table.polygon_object_latlng_buffer_<D>m: For an inclusive
        buffer of D metres around the storm.
    storm_object_table.polygon_object_latlng_buffer_<d>_<D>m: For an exclusive
        buffer of d...D metres around the storm.
    """

    error_checking.assert_is_geq_numpy_array(
        min_distances_metres, 0., allow_nan=True)
    error_checking.assert_is_numpy_array(
        min_distances_metres, num_dimensions=1)

    num_buffers = len(min_distances_metres)
    error_checking.assert_is_geq_numpy_array(
        max_distances_metres, 0., allow_nan=False)
    error_checking.assert_is_numpy_array(
        max_distances_metres, exact_dimensions=numpy.array([num_buffers]))

    for j in range(num_buffers):
        if numpy.isnan(min_distances_metres[j]):
            continue
        error_checking.assert_is_greater(
            max_distances_metres[j], min_distances_metres[j],
            allow_nan=False)

    num_storm_objects = len(storm_object_table.index)
    centroid_latitudes_deg = numpy.full(num_storm_objects, numpy.nan)
    centroid_longitudes_deg = numpy.full(num_storm_objects, numpy.nan)

    for i in range(num_storm_objects):
        this_centroid_object = storm_object_table[
            POLYGON_OBJECT_LATLNG_COLUMN].values[0].centroid
        centroid_latitudes_deg[i] = this_centroid_object.y
        centroid_longitudes_deg[i] = this_centroid_object.x

    (global_centroid_lat_deg, global_centroid_lng_deg
    ) = geodetic_utils.get_latlng_centroid(
        latitudes_deg=centroid_latitudes_deg,
        longitudes_deg=centroid_longitudes_deg)
    projection_object = projections.init_azimuthal_equidistant_projection(
        global_centroid_lat_deg, global_centroid_lng_deg)

    object_array = numpy.full(num_storm_objects, numpy.nan, dtype=object)
    argument_dict = {}
    buffer_column_names = [''] * num_buffers

    for j in range(num_buffers):
        buffer_column_names[j] = distance_buffer_to_column_name(
            min_distances_metres[j], max_distances_metres[j])
        argument_dict.update({buffer_column_names[j]: object_array})
    storm_object_table = storm_object_table.assign(**argument_dict)

    for i in range(num_storm_objects):
        orig_vertex_dict_latlng = polygons.polygon_object_to_vertex_arrays(
            storm_object_table[POLYGON_OBJECT_LATLNG_COLUMN].values[i])

        (orig_vertex_x_metres,
         orig_vertex_y_metres) = projections.project_latlng_to_xy(
             orig_vertex_dict_latlng[polygons.EXTERIOR_Y_COLUMN],
             orig_vertex_dict_latlng[polygons.EXTERIOR_X_COLUMN],
             projection_object=projection_object)

        for j in range(num_buffers):
            buffer_polygon_object_xy = polygons.buffer_simple_polygon(
                orig_vertex_x_metres, orig_vertex_y_metres,
                min_buffer_dist_metres=min_distances_metres[j],
                max_buffer_dist_metres=max_distances_metres[j])

            buffer_vertex_dict = polygons.polygon_object_to_vertex_arrays(
                buffer_polygon_object_xy)

            (buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
             buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN]) = (
                 projections.project_xy_to_latlng(
                     buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN],
                     buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
                     projection_object=projection_object))

            this_num_holes = len(buffer_vertex_dict[polygons.HOLE_X_COLUMN])
            for k in range(this_num_holes):
                (buffer_vertex_dict[polygons.HOLE_Y_COLUMN][k],
                 buffer_vertex_dict[polygons.HOLE_X_COLUMN][k]) = (
                     projections.project_xy_to_latlng(
                         buffer_vertex_dict[polygons.HOLE_X_COLUMN][k],
                         buffer_vertex_dict[polygons.HOLE_Y_COLUMN][k],
                         projection_object=projection_object))

            buffer_polygon_object_latlng = (
                polygons.vertex_arrays_to_polygon_object(
                    buffer_vertex_dict[polygons.EXTERIOR_X_COLUMN],
                    buffer_vertex_dict[polygons.EXTERIOR_Y_COLUMN],
                    hole_x_coords_list=
                    buffer_vertex_dict[polygons.HOLE_X_COLUMN],
                    hole_y_coords_list=
                    buffer_vertex_dict[polygons.HOLE_Y_COLUMN]))

            storm_object_table[buffer_column_names[j]].values[
                i] = buffer_polygon_object_latlng

    return storm_object_table
Пример #12
0
def _run(input_shapefile_name, output_pickle_file_name):
    """Converts SPC convective outlook to nicer file format.

    This is effectively the main method.

    :param input_shapefile_name: See documentation at top of file.
    :param output_pickle_file_name: Same.
    """

    projection_object = projections.init_lcc_projection(
        standard_latitudes_deg=STANDARD_LATITUDES_DEG,
        central_longitude_deg=CENTRAL_LONGITUDE_DEG,
        ellipsoid_name=ELLIPSOID_NAME)

    print('Reading data from: "{0:s}"...'.format(input_shapefile_name))
    shapefile_handle = shapefile.Reader(input_shapefile_name)

    list_of_polygon_objects_latlng = []
    risk_type_strings = []

    for this_record_object in shapefile_handle.iterShapeRecords():
        # print this_record_object.record
        this_risk_type_enum = this_record_object.record[RISK_TYPE_INDEX]

        try:
            this_risk_type_string = RISK_TYPE_ENUM_TO_STRING[
                this_risk_type_enum]
        except KeyError:
            continue

        these_xy_tuples = this_record_object.shape.points
        this_num_vertices = len(these_xy_tuples)

        these_x_coords_metres = numpy.array(
            [these_xy_tuples[k][0] for k in range(this_num_vertices)])

        these_y_coords_metres = numpy.array(
            [these_xy_tuples[k][1] for k in range(this_num_vertices)])

        these_latitudes_deg, these_longitudes_deg = (
            projections.project_xy_to_latlng(
                x_coords_metres=these_x_coords_metres,
                y_coords_metres=these_y_coords_metres,
                projection_object=projection_object,
                false_easting_metres=FALSE_EASTING_METRES,
                false_northing_metres=FALSE_NORTHING_METRES))

        this_polygon_object_latlng = (polygons.vertex_arrays_to_polygon_object(
            exterior_x_coords=these_longitudes_deg,
            exterior_y_coords=these_latitudes_deg))

        risk_type_strings.append(this_risk_type_string)
        list_of_polygon_objects_latlng.append(this_polygon_object_latlng)

    outlook_dict = {
        RISK_TYPE_COLUMN: risk_type_strings,
        POLYGON_COLUMN: list_of_polygon_objects_latlng
    }

    outlook_table = pandas.DataFrame.from_dict(outlook_dict)
    # print(outlook_table)

    print('Writing outlook polygons to file: "{0:s}"...'.format(
        output_pickle_file_name))

    file_system_utils.mkdir_recursive_if_necessary(
        file_name=output_pickle_file_name)

    pickle_file_handle = open(output_pickle_file_name, 'wb')
    pickle.dump(outlook_table, pickle_file_handle)
    pickle_file_handle.close()