def _project_polygon_latlng_to_xy(polygon_object_latlng, centroid_latitude_deg=None, centroid_longitude_deg=None): """Projects polygon from lat-long to x-y coordinates. :param polygon_object_latlng: Instance of `shapely.geometry.Polygon`, where x-coordinates are actually longitudes and y-coordinates are actually latitudes. :param centroid_latitude_deg: Latitude (deg N) at polygon centroid. :param centroid_longitude_deg: Longitude (deg E) at polygon centroid. :return: polygon_object_xy: Instance of `shapely.geometry.Polygon`, where x- and y-coordinates are in metres. """ projection_object = projections.init_lcc_projection( standard_latitudes_deg=numpy.full(2, centroid_latitude_deg), central_longitude_deg=centroid_longitude_deg) vertex_latitudes_deg = numpy.asarray(polygon_object_latlng.exterior.xy[1]) vertex_longitudes_deg = numpy.asarray(polygon_object_latlng.exterior.xy[0]) vertex_x_metres, vertex_y_metres = projections.project_latlng_to_xy( vertex_latitudes_deg, vertex_longitudes_deg, projection_object=projection_object, false_easting_metres=0., false_northing_metres=0.) return polygons.vertex_arrays_to_polygon_object( vertex_x_metres, vertex_y_metres)
def init_projection(model_name): """Initializes projection used by model. :param model_name: Model name (must be accepted by `check_model_name`). :return: projection_object: Instance of `pyproj.Proj`, specifying the projection. """ standard_latitudes_deg, central_longitude_deg = get_projection_params( model_name) return projections.init_lcc_projection( standard_latitudes_deg=standard_latitudes_deg, central_longitude_deg=central_longitude_deg)
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)
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 _get_grid_point_coords(model_name, first_row_in_full_grid, last_row_in_full_grid, first_column_in_full_grid, last_column_in_full_grid, grid_id=None, basemap_object=None): """Returns x-y and lat-long coords for a subgrid of the full model grid. This method generates different x-y coordinates than `nwp_model_utils.get_xy_grid_point_matrices`, because (like `mpl_toolkits.basemap.Basemap`) this method sets false easting = false northing = 0 metres. :param model_name: Name of NWP model (must be accepted by `nwp_model_utils.check_grid_name`). :param first_row_in_full_grid: Row 0 in the subgrid is row `first_row_in_full_grid` in the full grid. :param last_row_in_full_grid: Last row in the subgrid is row `last_row_in_full_grid` in the full grid. If you want last row in the subgrid to equal last row in the full grid, make this -1. :param first_column_in_full_grid: Column 0 in the subgrid is column `first_column_in_full_grid` in the full grid. :param last_column_in_full_grid: Last column in the subgrid is column `last_column_in_full_grid` in the full grid. If you want last column in the subgrid to equal last column in the full grid, make this -1. :param grid_id: Grid for NWP model (must be accepted by `nwp_model_utils.check_grid_name`). :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap` for the given NWP model. If you don't have one, no big deal -- leave this argument empty. :return: coordinate_dict: Dictionary with the following keys. coordinate_dict['grid_point_x_matrix_metres']: M-by-N numpy array of x-coordinates. coordinate_dict['grid_point_y_matrix_metres']: M-by-N numpy array of y-coordinates. coordinate_dict['grid_point_lat_matrix_deg']: M-by-N numpy array of latitudes (deg N). coordinate_dict['grid_point_lng_matrix_deg']: M-by-N numpy array of longitudes (deg E). """ num_rows_in_full_grid, num_columns_in_full_grid = ( nwp_model_utils.get_grid_dimensions(model_name=model_name, grid_name=grid_id)) error_checking.assert_is_integer(first_row_in_full_grid) error_checking.assert_is_geq(first_row_in_full_grid, 0) error_checking.assert_is_integer(last_row_in_full_grid) if last_row_in_full_grid < 0: last_row_in_full_grid += num_rows_in_full_grid error_checking.assert_is_greater(last_row_in_full_grid, first_row_in_full_grid) error_checking.assert_is_less_than(last_row_in_full_grid, num_rows_in_full_grid) error_checking.assert_is_integer(first_column_in_full_grid) error_checking.assert_is_geq(first_column_in_full_grid, 0) error_checking.assert_is_integer(last_column_in_full_grid) if last_column_in_full_grid < 0: last_column_in_full_grid += num_columns_in_full_grid error_checking.assert_is_greater(last_column_in_full_grid, first_column_in_full_grid) error_checking.assert_is_less_than(last_column_in_full_grid, num_columns_in_full_grid) grid_point_lat_matrix_deg, grid_point_lng_matrix_deg = ( nwp_model_utils.get_latlng_grid_point_matrices(model_name=model_name, grid_name=grid_id)) grid_point_lat_matrix_deg = grid_point_lat_matrix_deg[ first_row_in_full_grid:(last_row_in_full_grid + 1), first_column_in_full_grid:(last_column_in_full_grid + 1)] grid_point_lng_matrix_deg = grid_point_lng_matrix_deg[ first_row_in_full_grid:(last_row_in_full_grid + 1), first_column_in_full_grid:(last_column_in_full_grid + 1)] if basemap_object is None: standard_latitudes_deg, central_longitude_deg = ( nwp_model_utils.get_projection_params(model_name)) projection_object = projections.init_lcc_projection( standard_latitudes_deg=standard_latitudes_deg, central_longitude_deg=central_longitude_deg) grid_point_x_matrix_metres, grid_point_y_matrix_metres = ( projections.project_latlng_to_xy( latitudes_deg=grid_point_lat_matrix_deg, longitudes_deg=grid_point_lng_matrix_deg, projection_object=projection_object, false_northing_metres=0., false_easting_metres=0.)) else: grid_point_x_matrix_metres, grid_point_y_matrix_metres = basemap_object( grid_point_lng_matrix_deg, grid_point_lat_matrix_deg) return { X_COORD_MATRIX_KEY: grid_point_x_matrix_metres, Y_COORD_MATRIX_KEY: grid_point_y_matrix_metres, LATITUDE_MATRIX_KEY: grid_point_lat_matrix_deg, LONGITUDE_MATRIX_KEY: grid_point_lng_matrix_deg, }
def test_init_lcc_projection_no_crash(self): """Ensures that init_lcc_projection does not crash.""" projections.init_lcc_projection( standard_latitudes_deg=STANDARD_LATITUDES_DEG, central_longitude_deg=CENTRAL_LONGITUDE_DEG)
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()
def create_equidistant_grid(min_latitude_deg, max_latitude_deg, min_longitude_deg, max_longitude_deg, x_spacing_metres, y_spacing_metres, azimuthal=True): """Creates equidistant grid. M = number of rows N = number of columns :param min_latitude_deg: Minimum latitude (deg N) in grid. :param max_latitude_deg: Max latitude (deg N) in grid. :param min_longitude_deg: Minimum longitude (deg E) in grid. :param max_longitude_deg: Max longitude (deg E) in grid. :param x_spacing_metres: Spacing between grid points in adjacent columns. :param y_spacing_metres: Spacing between grid points in adjacent rows. :param azimuthal: Boolean flag. If True, will create azimuthal equidistant grid. If False, will create Lambert conformal grid. :return: grid_dict: Dictionary with the following keys. grid_dict['grid_point_x_coords_metres']: length-N numpy array with unique x-coordinates at grid points. grid_dict['grid_point_y_coords_metres']: length-M numpy array with unique y-coordinates at grid points. grid_dict['projection_object']: Instance of `pyproj.Proj` (used to convert between lat-long coordinates and the x-y coordinates of the grid). """ # Check input args. error_checking.assert_is_valid_latitude(min_latitude_deg) error_checking.assert_is_valid_latitude(max_latitude_deg) error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg) error_checking.assert_is_greater(x_spacing_metres, 0.) error_checking.assert_is_greater(y_spacing_metres, 0.) error_checking.assert_is_boolean(azimuthal) min_longitude_deg = lng_conversion.convert_lng_negative_in_west( min_longitude_deg, allow_nan=False) max_longitude_deg = lng_conversion.convert_lng_negative_in_west( max_longitude_deg, allow_nan=False) error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg) # Create lat-long grid. num_grid_rows = 1 + int( numpy.round((max_latitude_deg - min_latitude_deg) / DUMMY_LATITUDE_SPACING_DEG)) num_grid_columns = 1 + int( numpy.round((max_longitude_deg - min_longitude_deg) / DUMMY_LONGITUDE_SPACING_DEG)) unique_latitudes_deg, unique_longitudes_deg = get_latlng_grid_points( min_latitude_deg=min_latitude_deg, min_longitude_deg=min_longitude_deg, lat_spacing_deg=DUMMY_LATITUDE_SPACING_DEG, lng_spacing_deg=DUMMY_LONGITUDE_SPACING_DEG, num_rows=num_grid_rows, num_columns=num_grid_columns) latitude_matrix_deg, longitude_matrix_deg = latlng_vectors_to_matrices( unique_latitudes_deg=unique_latitudes_deg, unique_longitudes_deg=unique_longitudes_deg) # Create projection. central_latitude_deg = 0.5 * (min_latitude_deg + max_latitude_deg) central_longitude_deg = 0.5 * (min_longitude_deg + max_longitude_deg) if azimuthal: projection_object = projections.init_azimuthal_equidistant_projection( central_latitude_deg=central_latitude_deg, central_longitude_deg=central_longitude_deg) else: projection_object = projections.init_lcc_projection( standard_latitudes_deg=numpy.full(2, central_latitude_deg), central_longitude_deg=central_longitude_deg) # Convert lat-long grid to preliminary x-y grid. prelim_x_matrix_metres, prelim_y_matrix_metres = ( projections.project_latlng_to_xy(latitudes_deg=latitude_matrix_deg, longitudes_deg=longitude_matrix_deg, projection_object=projection_object)) # Find corners of preliminary x-y grid. x_min_metres = numpy.min(prelim_x_matrix_metres) x_max_metres = numpy.max(prelim_x_matrix_metres) y_min_metres = numpy.min(prelim_y_matrix_metres) y_max_metres = numpy.max(prelim_y_matrix_metres) # Find corners of final x-y grid. x_min_metres = number_rounding.floor_to_nearest(x_min_metres, x_spacing_metres) x_max_metres = number_rounding.ceiling_to_nearest(x_max_metres, x_spacing_metres) y_min_metres = number_rounding.floor_to_nearest(y_min_metres, y_spacing_metres) y_max_metres = number_rounding.ceiling_to_nearest(y_max_metres, y_spacing_metres) # Create final x-y grid. num_grid_rows = 1 + int( numpy.round((y_max_metres - y_min_metres) / y_spacing_metres)) num_grid_columns = 1 + int( numpy.round((x_max_metres - x_min_metres) / x_spacing_metres)) unique_x_coords_metres, unique_y_coords_metres = get_xy_grid_points( x_min_metres=x_min_metres, y_min_metres=y_min_metres, x_spacing_metres=x_spacing_metres, y_spacing_metres=y_spacing_metres, num_rows=num_grid_rows, num_columns=num_grid_columns) return { X_COORDS_KEY: unique_x_coords_metres, Y_COORDS_KEY: unique_y_coords_metres, PROJECTION_KEY: projection_object }