def _proj4_str_to_dict(self, proj4_string): """ Converts PROJ4 compatible string to dictionary. Parameters ---------- proj4_string : str PROJ4 parameters as a string (e.g., '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs'). Returns ------- dict Dictionary containing PROJ4 parameters. Notes ----- Key only parameters will be assigned a value of `True`. EPSG codes should be provided as "EPSG:XXXX" where "XXXX" is the EPSG code number. It can also be provided as "+init=EPSG:XXXX" as long as the underlying PROJ library supports it (deprecated in PROJ 6.0+). """ # convert EPSG codes to equivalent PROJ4 string definition if proj4_string.lower().startswith('epsg:'): crs = CRS(proj4_string) return crs.to_dict() else: proj4_pairs = (x.split('=', 1) for x in proj4_string.replace('+', '').split(" ")) return self.__convert_proj4_pairs_to_dict(proj4_pairs)
def test_set_vector_file_wrong_fail(self): """Test set_vector_file with wrong centroids""" shp_file = shapereader.natural_earth(resolution='110m', category='cultural', name='populated_places_simple') centr = Centroids() inten = centr.set_vector_file(shp_file, ['pop_min', 'pop_max']) self.assertEqual(CRS.from_user_input(centr.geometry.crs), CRS.from_epsg(u_coord.NE_EPSG)) self.assertEqual(centr.geometry.size, centr.lat.size) self.assertEqual(CRS.from_user_input(centr.geometry.crs), CRS.from_epsg(u_coord.NE_EPSG)) self.assertAlmostEqual(centr.lon[0], 12.453386544971766) self.assertAlmostEqual(centr.lon[-1], 114.18306345846304) self.assertAlmostEqual(centr.lat[0], 41.903282179960115) self.assertAlmostEqual(centr.lat[-1], 22.30692675357551) self.assertEqual(inten.shape, (2, 243)) # population min self.assertEqual(inten[0, 0], 832) self.assertEqual(inten[0, -1], 4551579) # population max self.assertEqual(inten[1, 0], 832) self.assertEqual(inten[1, -1], 7206000) shp_file = shapereader.natural_earth(resolution='10m', category='cultural', name='populated_places_simple') with self.assertRaises(ValueError): centr.set_vector_file(shp_file, ['pop_min', 'pop_max'])
async def get_wms_image(tile, source, session): bounds = list(mercantile.bounds(tile)) if "available_projections" not in source["properties"]: return None available_projections = source["properties"]["available_projections"] url = source["properties"]["url"] proj = None if "EPSG:4326" in available_projections: proj = "EPSG:4326" elif "EPSG:3857" in available_projections: proj = "EPSG:3857" else: for proj in sorted(available_projections): try: CRS.from_string(proj) except: continue break if proj is None: return None wms_version = wms_version_from_url(url) bbox = _get_bbox(proj, bounds, wms_version) if bbox is None: return None formatted_url = url.format(proj=proj, width=256, height=256, bbox=bbox) return formatted_url
def _get_bbox(proj, bounds, wms_version): """ Build wms bbox parameter for GetMap request""" if proj in {"EPSG:4326", "CRS:84"}: if proj == "EPSG:4326" and wms_version == "1.3.0": bbox = ",".join( map(str, [bounds[1], bounds[0], bounds[3], bounds[2]])) else: bbox = ",".join(map(str, bounds)) else: try: crs_from = CRS.from_string("epsg:4326") crs_to = CRS.from_string(proj) transformer = get_transformer(crs_from, crs_to) bounds = list(transformer.transform(bounds[0], bounds[1])) + list( transformer.transform(bounds[2], bounds[3])) except: return None # WMS < 1.3.0 assumes x,y coordinate ordering. # WMS 1.3.0 expects coordinate ordering defined in CRS. # if crs_to.axis_info[0].direction == "north" and wms_version == "1.3.0": bbox = ",".join( map(str, [bounds[1], bounds[0], bounds[3], bounds[2]])) else: bbox = ",".join(map(str, bounds)) return bbox
def test_to_crs_user_input(self): pcrs = PCRS.from_epsg(4326) rcrs = RCRS.from_epsg(4326) # are they the default? self.assertTrue( pcrs == PCRS.from_user_input(to_crs_user_input(DEF_CRS))) self.assertEqual(rcrs, RCRS.from_user_input(to_crs_user_input(DEF_CRS))) # can they be understood from the provider? for arg in ['epsg:4326', b'epsg:4326', DEF_CRS, 4326]: self.assertEqual(pcrs, PCRS.from_user_input(to_crs_user_input(arg))) self.assertEqual(rcrs, RCRS.from_user_input(to_crs_user_input(arg))) # can they be misunderstood from the provider? for arg in [{ 'init': 'epsg:4326', 'no_defs': True }, b'{"init": "epsg:4326", "no_defs": True}']: self.assertFalse( pcrs == PCRS.from_user_input(to_crs_user_input(arg))) self.assertEqual(rcrs, RCRS.from_user_input(to_crs_user_input(arg))) # are they noticed? for arg in [4326.0, [4326]]: with self.assertRaises(ValueError): to_crs_user_input(arg) with self.assertRaises(SyntaxError): to_crs_user_input('{init: epsg:4326, no_defs: True}')
def __init__(self, *args, local_crs: int = None, x_col: str = None, y_col: str = None, z_col: str = None, time_col: str = None, time_sort: bool = True, **kwargs) -> '_GpsBase': # Get data data = kwargs.get("data", None) if data is None and len(args) > 0: data = args[0] if isinstance(data, (_GpsBase, pd.core.internals.managers.BlockManager)): is_base = True else: is_base = False # Create a GeoDataFrame df = gpd.GeoDataFrame(*args, **kwargs) # Set CRS if df.crs is None: try: df.crs = data.crs except AttributeError: df.crs = self._default_input_crs if not is_base: # Get default values x_col = x_col if x_col is not None else self._default_x_col y_col = y_col if y_col is not None else self._default_y_col z_col = z_col if z_col is not None else self._default_z_col time_col = time_col if time_col is not None else self._default_time_col # Format data self._format_data( df, x_col, y_col, z_col, time_col, time_sort, ) # Project data if local_crs is not None: self_crs = CRS(df.crs) local_crs = CRS(local_crs) if local_crs != self_crs: df.to_crs(local_crs, inplace=True) # Compute normalized data if not is_base and self._has_time: self._normalize_data(df) super(_GpsBase, self).__init__(df, crs=df.crs)
def _transform_to_coordinates(self, x, y): if self.file.crs == CRS("EPSG:4326"): return Point(y, x) transformer = Transformer.from_proj(self.file.crs, CRS("EPSG:4326")) lat, lon = transformer.transform(x, y) lon = abs(lon + 90) if abs(lon - 90) > abs(lon - 180): if abs(lon - 180) > abs(lon - 270): lon = abs(270 - lon) + 90 else: lon = lon - 90 return Point(lat, lon)
def test_proj(proj): if proj == 'CRS:84': return True if 'AUTO' in proj: return False if 'EPSG' in proj: try: CRS.from_string(proj) return True except: return False return False
def test_bound_crs_crs__from_methods(): crs_str = "+proj=latlon +towgs84=0,0,0" with pytest.raises(CRSError, match="Invalid type"): BoundCRS.from_epsg(4326) assert_maker_inheritance_valid(BoundCRS.from_string(crs_str), BoundCRS) assert_maker_inheritance_valid(BoundCRS.from_proj4(crs_str), BoundCRS) assert_maker_inheritance_valid( BoundCRS.from_user_input(BoundCRS.from_string(crs_str)), BoundCRS) assert_maker_inheritance_valid(BoundCRS.from_json(CRS(crs_str).to_json()), BoundCRS) assert_maker_inheritance_valid( BoundCRS.from_json_dict(CRS(crs_str).to_json_dict()), BoundCRS)
def test_vertical_crs__from_methods(): assert_maker_inheritance_valid(VerticalCRS.from_epsg(5703), VerticalCRS) assert_maker_inheritance_valid(VerticalCRS.from_string("EPSG:5703"), VerticalCRS) with pytest.raises(CRSError, match="Invalid type"): VerticalCRS.from_proj4("+proj=latlon") assert_maker_inheritance_valid( VerticalCRS.from_user_input(VerticalCRS.from_string("EPSG:5703")), VerticalCRS) assert_maker_inheritance_valid(VerticalCRS.from_json(CRS(5703).to_json()), VerticalCRS) assert_maker_inheritance_valid( VerticalCRS.from_json_dict(CRS(5703).to_json_dict()), VerticalCRS)
def proj4_radius_parameters(proj4_dict): """Calculate 'a' and 'b' radius parameters. Arguments: proj4_dict (str or dict): PROJ.4 parameters Returns: a (float), b (float): equatorial and polar radius """ if CRS is not None: import math crs = CRS(proj4_dict) a = crs.ellipsoid.semi_major_metre b = crs.ellipsoid.semi_minor_metre if not math.isnan(b): return a, b # older versions of pyproj didn't always have a valid minor radius proj4_dict = crs.to_dict() if isinstance(proj4_dict, str): new_info = proj4_str_to_dict(proj4_dict) else: new_info = proj4_dict.copy() # load information from PROJ.4 about the ellipsis if possible from pyproj import Geod if 'ellps' in new_info: geod = Geod(**new_info) new_info['a'] = geod.a new_info['b'] = geod.b elif 'a' not in new_info or 'b' not in new_info: if 'rf' in new_info and 'f' not in new_info: new_info['f'] = 1. / float(new_info['rf']) if 'a' in new_info and 'f' in new_info: new_info['b'] = float(new_info['a']) * (1 - float(new_info['f'])) elif 'b' in new_info and 'f' in new_info: new_info['a'] = float(new_info['b']) / (1 - float(new_info['f'])) elif 'R' in new_info: new_info['a'] = new_info['R'] new_info['b'] = new_info['R'] else: geod = Geod(**{'ellps': 'WGS84'}) new_info['a'] = geod.a new_info['b'] = geod.b return float(new_info['a']), float(new_info['b'])
def pyproj_crs_to_osgeo(proj_crs: Union[CRS, int]): """ Convert from the pyproj CRS object to osgeo SpatialReference See https://pyproj4.github.io/pyproj/stable/crs_compatibility.html Parameters ---------- proj_crs pyproj CRS or an integer epsg code Returns ------- SpatialReference converted SpatialReference """ if isinstance(proj_crs, int): proj_crs = CRS.from_epsg(proj_crs) osr_crs = SpatialReference() if osgeo.version_info.major < 3: osr_crs.ImportFromWkt(proj_crs.to_wkt(WktVersion.WKT1_GDAL)) else: osr_crs.ImportFromWkt(proj_crs.to_wkt()) return osr_crs
def test_projected_crs__from_methods(): assert_maker_inheritance_valid(ProjectedCRS.from_epsg(6933), ProjectedCRS) assert_maker_inheritance_valid(ProjectedCRS.from_string("EPSG:6933"), ProjectedCRS) assert_maker_inheritance_valid( ProjectedCRS.from_proj4("+proj=aea +lat_1=1"), ProjectedCRS) assert_maker_inheritance_valid( ProjectedCRS.from_user_input(ProjectedCRS.from_string("EPSG:6933")), ProjectedCRS, ) assert_maker_inheritance_valid(ProjectedCRS.from_json(CRS(6933).to_json()), ProjectedCRS) assert_maker_inheritance_valid( ProjectedCRS.from_json_dict(CRS(6933).to_json_dict()), ProjectedCRS) with pytest.raises(CRSError, match="Invalid type"): ProjectedCRS.from_epsg(4326)
def _proj4_str_to_dict(self, proj4_str): """Convert PROJ.4 compatible string definition to dict EPSG codes should be provided as "EPSG:XXXX" where "XXXX" is the EPSG number code. It can also be provided as ``"+init=EPSG:XXXX"`` as long as the underlying PROJ library supports it (deprecated in PROJ 6.0+). Note: Key only parameters will be assigned a value of `True`. """ # TODO: @shahn I would got for one solution, i.e. PyProj > 2.2 # TODO: test if this can be simplified # # convert EPSG codes to equivalent PROJ4 string definition if proj4_str.startswith('EPSG:'): crs = CRS(proj4_str) return crs.to_dict() else: proj4_pairs = (x.split('=', 1) for x in proj4_str.replace('+', '').split(" ")) return self.__convert_proj4_pairs_to_dict(proj4_pairs)
def test_geographic_crs__from_methods(): assert_maker_inheritance_valid(GeographicCRS.from_epsg(4326), GeographicCRS) assert_maker_inheritance_valid(GeographicCRS.from_string("EPSG:4326"), GeographicCRS) assert_maker_inheritance_valid(GeographicCRS.from_proj4("+proj=latlon"), GeographicCRS) assert_maker_inheritance_valid( GeographicCRS.from_user_input(GeographicCRS.from_string("EPSG:4326")), GeographicCRS, ) assert_maker_inheritance_valid( GeographicCRS.from_json(CRS(4326).to_json()), GeographicCRS) assert_maker_inheritance_valid( GeographicCRS.from_json_dict(CRS(4326).to_json_dict()), GeographicCRS) with pytest.raises(CRSError, match="Invalid type"): GeographicCRS.from_epsg(6933)
def split_linestring_df(df: Union[pd.DataFrame, gpd.GeoDataFrame], max_length: float, pool: Pool = None, **kwargs) -> gpd.GeoDataFrame: """ Splits the LineString existing in a data frame based on the provided `max_length`. All the other columns are retpeated untouched. :param df: The input `DataFrame` or `GeoDataFrame` :param max_length: The maximum length that each LineString is allowed to have. Has not effect on other geometry t types. :param pool: A pool of parallel workers to speed up processing large data frames. :param kwargs: Extra keywords controlling the behavior of this function. Currently available keywords are: - 'length_epsg`: the EPSG that the max_length is provided. The default is EPSG:3857 hence, the `max_length` is assumed to be meter. - `geom_field`: The name of the column containing the geometry. Default is 'geometry'. - `part_id_field`: The name of the columns to be added to the output which identifies different parts of the same geometry. Default is `part_id`. :return: a new `GeoDataFrame` where LineString or MultiLineStrings do not exceed the `max_length` """ length_epsg = kwargs.get('length_epsg', 3857) length_crs = CRS(length_epsg) original_crs = None if length_crs.name == df.crs.name else df.crs df = df if length_crs.name == df.crs.name else df.to_crs(length_crs) geom_field = kwargs.get('geom_field', 'geometry') split_geometry = split_linestring(geometry=df[geom_field], max_length=max_length, pool=pool) part_id_field = kwargs.get('part_id_field', 'part_id') output = pd.concat([ gpd.GeoDataFrame( data={ key: ( [row[1][key]] * len(split_geometry[row[0]]) \ if key != part_id_field \ else list(range(len(split_geometry[row[0]]))) ) for key in list(row[1].keys()) + [part_id_field] if key != geom_field }, geometry=split_geometry[row[0]] ) for row in df.iterrows() ]) output.reset_index(drop=True, inplace=True) output.crs = length_crs if original_crs is not None: output = output.to_crs(original_crs) return output
def __init__(self, code): crs = _CRS.from_epsg(code) if not crs.is_projected: raise ValueError('EPSG code does not define a projection') if not crs.area_of_use: raise ValueError("Area of use not defined.") self.epsg_code = code super().__init__(crs.to_wkt())
def test_proj(proj): if proj == "CRS:84": return True if "AUTO" in proj: return False # 'EPSG:102067' is not valid, should be ESRI:102067: https://epsg.io/102067 if proj == "EPSG:102067": return False # 'EPSG:102066' is not valid, should be ESRI:102066: https://epsg.io/102066 if proj == "EPSG:102066": return False if "EPSG" in proj: try: CRS.from_string(proj) return True except: return False return False
def from_rasterio(crs): """Converts from rasterio CRS to the workflow CRS standard. Parameters ---------- crs : rasterio-crs-object Input rasterio crs. Returns ------- out : crs-type Equivalent workflow CRS. """ try: # from authority seems to get better results with bounds? return CRS.from_authority(*crs.to_authority()) except Exception: return CRS.from_user_input(crs)
def build_valid_vert_crs(crs: pyproj_VerticalCRS, regions: [str], datum_data: object) -> (pyproj_VerticalCRS, str, str): """ Add the regions and pipeline to the remarks section of the wkt for the provided pyproj VerticalCRS object. Parameters ---------- crs : pyproj.crs.VerticalCRS The vertical crs object to add the pipeline and region into. regions : [str] The regions to add into the crs remarks. vdatum_version_string version of vdatum, used in the geoid/region lookup Returns ------- result (pyproj.crs.VerticalCRS, str) First value is the vertical crs object with the remarks updated to add the region and pipeline. The second value is the vyperdatum.pipeline datum identifier. The third value is the pipeline string. """ datum = guess_vertical_datum_from_string(crs.name) pipeline = None new_crs = VerticalPipelineCRS(datum_data=datum_data) new_crs.from_wkt(crs.to_wkt()) if datum: for region in regions: if datum == 'ellipse': new_pipeline = '[]' else: geoid_name = datum_data.get_geoid_name(region) new_pipeline = get_regional_pipeline('ellipse', datum, region, geoid_name) if new_pipeline: new_crs.add_pipeline(new_pipeline, region) pipeline = new_crs.pipeline_string if datum == 'geoid': geoids = [ gd for gd in geoid_possibilities if pipeline.find(gd) != -1 ] if len(geoids) > 1: raise NotImplementedError( f'Found multiple geoids in the pipeline string, only one geoid per pipeline supported at this time: {geoids}' ) elif len(geoids) == 0: raise ValueError( f'No geoid found in given pipeline string: {pipeline}') newdatum = geoids[0] new_crs.datum_name = newdatum valid_vert_crs = CRS.from_wkt(new_crs.to_wkt()) else: valid_vert_crs = None return valid_vert_crs, datum, pipeline
def _convert_units(var, name: str, units: str, p: Proj, crs: CRS, inverse: bool = False, center=None): """Converts units from lon/lat to projection coordinates (meters). If `inverse` it True then the inverse calculation is done. """ if var is None: return None if isinstance(var, DataArray): units = var.units var = tuple(var.data.tolist()) if crs.is_geographic and not ('deg' == units or 'degrees' == units): raise ValueError( 'latlon/latlong projection cannot take {0} as units: {1}'.format( units, name)) # Check if units are an angle. is_angle = ('deg' == units or 'degrees' == units) if ('deg' in units) and not is_angle: logging.warning('units provided to {0} are incorrect: {1}'.format( name, units)) # Convert from var projection units to projection units given by projection from user. if not is_angle: if units == 'meters' or units == 'metres': units = 'm' if _get_proj_units(crs) != units: tmp_proj_dict = crs.to_dict() tmp_proj_dict['units'] = units transformer = Transformer.from_crs(tmp_proj_dict, p.crs) var = transformer.transform(*var) if name == 'center': var = _round_poles(var, units, p) # Return either degrees or meters depending on if the inverse is true or not. # Don't convert if inverse is True: Want degrees. # Converts list-like from degrees to meters. if is_angle and not inverse: if name in ('radius', 'resolution'): var = _distance_from_center_forward(var, center, p) elif not crs.is_geographic: # only convert to meters # this allows geographic projections to use coordinates outside # normal lon/lat ranges (ex. -90/90) var = p(*var, errcheck=True) # Don't convert if inverse is False: Want meters. elif not is_angle and inverse: # Converts list-like from meters to degrees. var = p(*var, inverse=True, errcheck=True) if name in ['radius', 'resolution']: var = (abs(var[0]), abs(var[1])) return var
def _handler(self, request, response): shape_url = request.inputs["shape"][0].file projected_crs = request.inputs["projected_crs"][0].data extensions = [".gml", ".shp", ".gpkg", ".geojson", ".json"] vector_file = single_file_check( archive_sniffer(shape_url, working_dir=self.workdir, extensions=extensions)) shape_crs = crs_sniffer(vector_file) try: projection = CRS.from_epsg(projected_crs) if projection.is_geographic: msg = ( f"Desired CRS {projection.to_epsg()} is geographic. " "Areal analysis values will be in decimal-degree units.") LOGGER.warning(msg) except Exception as e: msg = f"{e}: Failed to parse CRS definition. Exiting." LOGGER.error(msg) raise Exception(msg) # TODO: It would be good to one day refactor this to make use of RavenPy utils and gis utilities properties = list() try: for i, layer_name in enumerate(fiona.listlayers(vector_file)): with fiona.open(vector_file, "r", crs=shape_crs, layer=i) as src: for feature in src: geom = shape(feature["geometry"]) multipolygon_check(geom) transformed = geom_transform(geom, source_crs=shape_crs, target_crs=projection) prop = {"id": feature["id"]} prop.update(feature["properties"]) prop.update(geom_prop(transformed)) # Recompute the centroid location using the original projection prop["centroid"] = geom_prop(geom)["centroid"] properties.append(prop) except Exception as e: msg = f"{e}: Failed to extract features from shape {vector_file}." LOGGER.error(msg) raise Exception(msg) response.outputs["properties"].data = json.dumps(properties) return response
def test_derived_geographic_crs__from_methods(): crs_str = "+proj=ob_tran +o_proj=longlat +o_lat_p=0 +o_lon_p=0 +lon_0=0" with pytest.raises(CRSError, match="Invalid type Geographic 2D CRS"): DerivedGeographicCRS.from_epsg(4326) assert_maker_inheritance_valid(DerivedGeographicCRS.from_string(crs_str), DerivedGeographicCRS) assert_maker_inheritance_valid(DerivedGeographicCRS.from_proj4(crs_str), DerivedGeographicCRS) assert_maker_inheritance_valid( DerivedGeographicCRS.from_user_input( DerivedGeographicCRS.from_string(crs_str)), DerivedGeographicCRS, ) assert_maker_inheritance_valid( DerivedGeographicCRS.from_json(CRS(crs_str).to_json()), DerivedGeographicCRS) assert_maker_inheritance_valid( DerivedGeographicCRS.from_json_dict(CRS(crs_str).to_json_dict()), DerivedGeographicCRS, )
def _is_longlat(crs): '''Test if CRS is in lat/long coordinates''' try: return crs['proj'] == 'longlat' except (KeyError, TypeError, AttributeError): pass projection = CRS(crs) try: return projection.is_geographic except AttributeError: return crs.to_dict().get('proj') == 'longlat'
def test_read_vector_pass(self): """Test one columns data""" shp_file = shapereader.natural_earth(resolution='110m', category='cultural', name='populated_places_simple') lat, lon, geometry, intensity = read_vector(shp_file, ['pop_min', 'pop_max']) self.assertEqual(PCRS.from_user_input(geometry.crs), PCRS.from_epsg(NE_EPSG)) self.assertEqual(geometry.size, lat.size) self.assertAlmostEqual(lon[0], 12.453386544971766) self.assertAlmostEqual(lon[-1], 114.18306345846304) self.assertAlmostEqual(lat[0], 41.903282179960115) self.assertAlmostEqual(lat[-1], 22.30692675357551) self.assertEqual(intensity.shape, (2, 243)) # population min self.assertEqual(intensity[0, 0], 832) self.assertEqual(intensity[0, -1], 4551579) # population max self.assertEqual(intensity[1, 0], 832) self.assertEqual(intensity[1, -1], 7206000)
def proj4_str_to_dict(proj4_str): """Convert PROJ.4 compatible string definition to dict EPSG codes should be provided as "EPSG:XXXX" where "XXXX" is the EPSG number code. It can also be provided as ``"+init=EPSG:XXXX"`` as long as the underlying PROJ library supports it (deprecated in PROJ 6.0+). Note: Key only parameters will be assigned a value of `True`. """ # convert EPSG codes to equivalent PROJ4 string definition if proj4_str.startswith('EPSG:') and CRS is not None: crs = CRS(proj4_str) if hasattr(crs, 'to_dict'): # pyproj 2.2+ return crs.to_dict() proj4_str = crs.to_proj4() elif proj4_str.startswith('EPSG:'): # legacy +init= PROJ4 string and no pyproj 2.0+ to help convert proj4_str = "+init={}".format(proj4_str) pairs = (x.split('=', 1) for x in proj4_str.replace('+', '').split(" ")) return convert_proj_floats(pairs)
def from_fiona(crs): """Converts a fiona CRS to the workflow CRS standard. Parameters ---------- crs : fiona-crs-dict Input fiona CRS, which is a dictionary containing an EPSG code. Returns ------- out : crs-type Equivalent workflow CRS. """ # if 'datum' in crs and crs['datum'] == 'WGS84' and 'epsg' not in crs and 'ellps' not in crs: # logging.warning('Old-style datum WGS84, moving to ellipse') # crs['ellps'] = crs.pop('datum') if 'init' in crs and crs['init'].startswith('epsg:'): epsg, code = crs['init'].split(':') return CRS.from_epsg(code) else: return CRS.from_dict(crs)
def find_inlet_nodes(nodes, inlets_shp, gdobj): """ Load inlets from a shapefile. Loads the user-defined inlet nodes point shapefile and uses it to identify the inlet nodes within the network. Parameters ---------- links : dict stores the network's links and their properties inlets_shp : str path to the shapefile of inlet locations (point shapefile) gdobj : osgeo.gdal.Dataset gdal object corresponding to the georeferenced input binary channel mask Returns ------- nodes : dict nodes dictionary with 'inlets' key containing list of inlet node ids """ # Check that CRSs match; reproject inlet points if not inlets_gpd = gpd.read_file(inlets_shp) mask_crs = CRS(gdobj.GetProjection()) if inlets_gpd.crs != mask_crs: inlets_gpd = inlets_gpd.to_crs(mask_crs) logger.info( 'Provided inlet points file does not have the same CRS as provided mask. Reprojecting.' ) # Convert all nodes to xy coordinates for distance search nodes_xy = gu.idx_to_coords(nodes['idx'], gdobj) # Map provided inlet nodes to actual network nodes inlets = [] for inlet_geom in inlets_gpd.geometry.values: # Distances between inlet node and all nodes in network xy = inlet_geom.xy dists = np.sqrt((xy[0][0] - nodes_xy[0])**2 + (xy[1][0] - nodes_xy[1])**2) inlets.append(nodes['id'][np.argmin(dists)]) # Append inlets to nodes dict nodes['inlets'] = inlets return nodes
def from_epsg(epsg): """Converts from an EPSG code to a workflow CRS. Parameters ---------- epsg : int An EPSG code. (see `https://epsg.io`_) Returns ------- out : crs-type Equivalent workflow CRS. """ return CRS.from_epsg(epsg)
def from_cartopy(crs): """Converts a cartopy CRS to a workflow CRS. Parameters ---------- epsg : int An EPSG code. (see `https://epsg.io`_) Returns ------- out : crs-type Equivalent workflow CRS. """ return CRS.from_dict(crs.proj4_params)
def __init__(self, projparams=None, preserve_units=True, **kwargs): """ initialize a Proj class instance. See the proj documentation (https://github.com/OSGeo/proj.4/wiki) for more information about projection parameters. Parameters ---------- projparams: int, str, dict, pyproj.CRS A proj.4 or WKT string, proj.4 dict, EPSG integer, or a pyproj.CRS instnace. preserve_units: bool If false, will ensure +units=m. **kwargs: proj.4 projection parameters. Example usage: >>> from pyproj import Proj >>> p = Proj(proj='utm',zone=10,ellps='WGS84', preserve_units=False) # use kwargs >>> x,y = p(-120.108, 34.36116666) >>> 'x=%9.3f y=%11.3f' % (x,y) 'x=765975.641 y=3805993.134' >>> 'lon=%8.3f lat=%5.3f' % p(x,y,inverse=True) 'lon=-120.108 lat=34.361' >>> # do 3 cities at a time in a tuple (Fresno, LA, SF) >>> lons = (-119.72,-118.40,-122.38) >>> lats = (36.77, 33.93, 37.62 ) >>> x,y = p(lons, lats) >>> 'x: %9.3f %9.3f %9.3f' % x 'x: 792763.863 925321.537 554714.301' >>> 'y: %9.3f %9.3f %9.3f' % y 'y: 4074377.617 3763936.941 4163835.303' >>> lons, lats = p(x, y, inverse=True) # inverse transform >>> 'lons: %8.3f %8.3f %8.3f' % lons 'lons: -119.720 -118.400 -122.380' >>> 'lats: %8.3f %8.3f %8.3f' % lats 'lats: 36.770 33.930 37.620' >>> p2 = Proj('+proj=utm +zone=10 +ellps=WGS84', preserve_units=False) # use proj4 string >>> x,y = p2(-120.108, 34.36116666) >>> 'x=%9.3f y=%11.3f' % (x,y) 'x=765975.641 y=3805993.134' >>> p = Proj(init="epsg:32667", preserve_units=False) >>> 'x=%12.3f y=%12.3f (meters)' % p(-114.057222, 51.045) 'x=-1783506.250 y= 6193827.033 (meters)' >>> p = Proj("+init=epsg:32667") >>> 'x=%12.3f y=%12.3f (feet)' % p(-114.057222, 51.045) 'x=-5851386.754 y=20320914.191 (feet)' >>> # test data with radian inputs >>> p1 = Proj(init="epsg:4214") >>> x1, y1 = p1(116.366, 39.867) >>> '{:.3f} {:.3f}'.format(x1, y1) '2.031 0.696' >>> x2, y2 = p1(x1, y1, inverse=True) >>> '{:.3f} {:.3f}'.format(x2, y2) '116.366 39.867' """ self.crs = CRS.from_user_input(projparams if projparams is not None else kwargs) # make sure units are meters if preserve_units is False. if not preserve_units and "foot" in self.crs.axis_info[0].unit_name: projstring = self.crs.to_proj4(4) projstring = re.sub(r"\s\+units=[\w-]+", "", projstring) projstring += " +units=m" self.crs = CRS(projstring) super(Proj, self).__init__( cstrencode( (self.crs.to_proj4() or self.crs.srs).replace("+type=crs", "").strip() ) )
class Proj(_proj.Proj): """ performs cartographic transformations (converts from longitude,latitude to native map projection x,y coordinates and vice versa) using proj (https://github.com/OSGeo/proj.4/wiki). A Proj class instance is initialized with proj map projection control parameter key/value pairs. The key/value pairs can either be passed in a dictionary, or as keyword arguments, or as a proj4 string (compatible with the proj command). See http://www.remotesensing.org/geotiff/proj_list for examples of key/value pairs defining different map projections. Calling a Proj class instance with the arguments lon, lat will convert lon/lat (in degrees) to x/y native map projection coordinates (in meters). If optional keyword 'inverse' is True (default is False), the inverse transformation from x/y to lon/lat is performed. If optional keyword 'errcheck' is True (default is False) an exception is raised if the transformation is invalid. If errcheck=False and the transformation is invalid, no exception is raised and 1.e30 is returned. If the optional keyword 'preserve_units' is True, the units in map projection coordinates are not forced to be meters. Works with numpy and regular python array objects, python sequences and scalars. Attributes ---------- srs: str The string form of the user input used to create the Proj. crs: ~pyproj.crs.CRS The CRS object associated with the Proj. proj_version: int The major version number for PROJ. """ def __init__(self, projparams=None, preserve_units=True, **kwargs): """ initialize a Proj class instance. See the proj documentation (https://github.com/OSGeo/proj.4/wiki) for more information about projection parameters. Parameters ---------- projparams: int, str, dict, pyproj.CRS A proj.4 or WKT string, proj.4 dict, EPSG integer, or a pyproj.CRS instnace. preserve_units: bool If false, will ensure +units=m. **kwargs: proj.4 projection parameters. Example usage: >>> from pyproj import Proj >>> p = Proj(proj='utm',zone=10,ellps='WGS84', preserve_units=False) # use kwargs >>> x,y = p(-120.108, 34.36116666) >>> 'x=%9.3f y=%11.3f' % (x,y) 'x=765975.641 y=3805993.134' >>> 'lon=%8.3f lat=%5.3f' % p(x,y,inverse=True) 'lon=-120.108 lat=34.361' >>> # do 3 cities at a time in a tuple (Fresno, LA, SF) >>> lons = (-119.72,-118.40,-122.38) >>> lats = (36.77, 33.93, 37.62 ) >>> x,y = p(lons, lats) >>> 'x: %9.3f %9.3f %9.3f' % x 'x: 792763.863 925321.537 554714.301' >>> 'y: %9.3f %9.3f %9.3f' % y 'y: 4074377.617 3763936.941 4163835.303' >>> lons, lats = p(x, y, inverse=True) # inverse transform >>> 'lons: %8.3f %8.3f %8.3f' % lons 'lons: -119.720 -118.400 -122.380' >>> 'lats: %8.3f %8.3f %8.3f' % lats 'lats: 36.770 33.930 37.620' >>> p2 = Proj('+proj=utm +zone=10 +ellps=WGS84', preserve_units=False) # use proj4 string >>> x,y = p2(-120.108, 34.36116666) >>> 'x=%9.3f y=%11.3f' % (x,y) 'x=765975.641 y=3805993.134' >>> p = Proj(init="epsg:32667", preserve_units=False) >>> 'x=%12.3f y=%12.3f (meters)' % p(-114.057222, 51.045) 'x=-1783506.250 y= 6193827.033 (meters)' >>> p = Proj("+init=epsg:32667") >>> 'x=%12.3f y=%12.3f (feet)' % p(-114.057222, 51.045) 'x=-5851386.754 y=20320914.191 (feet)' >>> # test data with radian inputs >>> p1 = Proj(init="epsg:4214") >>> x1, y1 = p1(116.366, 39.867) >>> '{:.3f} {:.3f}'.format(x1, y1) '2.031 0.696' >>> x2, y2 = p1(x1, y1, inverse=True) >>> '{:.3f} {:.3f}'.format(x2, y2) '116.366 39.867' """ self.crs = CRS.from_user_input(projparams if projparams is not None else kwargs) # make sure units are meters if preserve_units is False. if not preserve_units and "foot" in self.crs.axis_info[0].unit_name: projstring = self.crs.to_proj4(4) projstring = re.sub(r"\s\+units=[\w-]+", "", projstring) projstring += " +units=m" self.crs = CRS(projstring) super(Proj, self).__init__( cstrencode( (self.crs.to_proj4() or self.crs.srs).replace("+type=crs", "").strip() ) ) def __call__(self, *args, **kw): # ,lon,lat,inverse=False,errcheck=False): """ Calling a Proj class instance with the arguments lon, lat will convert lon/lat (in degrees) to x/y native map projection coordinates (in meters). If optional keyword 'inverse' is True (default is False), the inverse transformation from x/y to lon/lat is performed. If optional keyword 'errcheck' is True (default is False) an exception is raised if the transformation is invalid. If errcheck=False and the transformation is invalid, no exception is raised and 1.e30 is returned. Inputs should be doubles (they will be cast to doubles if they are not, causing a slight performance hit). Works with numpy and regular python array objects, python sequences and scalars, but is fastest for array objects. """ inverse = kw.get("inverse", False) errcheck = kw.get("errcheck", False) # if len(args) == 1: # latlon = np.array(args[0], copy=True, # order='C', dtype=float, ndmin=2) # if inverse: # _proj.Proj._invn(self, latlon, radians=radians, errcheck=errcheck) # else: # _proj.Proj._fwdn(self, latlon, radians=radians, errcheck=errcheck) # return latlon lon, lat = args # process inputs, making copies that support buffer API. inx, xisfloat, xislist, xistuple = _copytobuffer(lon) iny, yisfloat, yislist, yistuple = _copytobuffer(lat) # call proj4 functions. inx and iny modified in place. if inverse: self._inv(inx, iny, errcheck=errcheck) else: self._fwd(inx, iny, errcheck=errcheck) # if inputs were lists, tuples or floats, convert back. outx = _convertback(xisfloat, xislist, xistuple, inx) outy = _convertback(yisfloat, yislist, xistuple, iny) return outx, outy def is_latlong(self): """ Returns ------- bool: True if projection in geographic (lon/lat) coordinates. """ warnings.warn( "'is_latlong()' is deprecated and will be removed in version 2.2.0. " "Please use 'crs.is_geographic'." ) return self.crs.is_geographic def is_geocent(self): """ Returns ------- bool: True if projection in geocentric (x/y) coordinates """ warnings.warn( "'is_geocent()' is deprecated and will be removed in version 2.2.0. " "Please use 'crs.is_geocent'." ) return self.is_geocent def definition_string(self): """Returns formal definition string for projection >>> Proj('+init=epsg:4326').definition_string() 'proj=longlat datum=WGS84 no_defs ellps=WGS84 towgs84=0,0,0' >>> """ return pystrdecode(self.definition) def to_latlong_def(self): """return the definition string of the geographic (lat/lon) coordinate version of the current projection""" # This is a little hacky way of getting a latlong proj object # Maybe instead of this function the __cinit__ function can take a # Proj object and a type (where type = "geographic") as the libproj # java wrapper return self.crs.to_geodetic().to_proj4(4) # deprecated : using in transform raised a TypeError in release 1.9.5.1 # reported in issue #53, resolved in #73. def to_latlong(self): """return a new Proj instance which is the geographic (lat/lon) coordinate version of the current projection""" return Proj(self.crs.to_geodetic())