def test_matchcrs(geometry_urb): bounds = geometry_urb.bounds points = ((bounds[0], bounds[2]), (bounds[1], bounds[3])) coords = MatchCRS.coords(points, DEF_CRS, ALT_CRS) bbox = MatchCRS.bounds(geometry_urb.bounds, DEF_CRS, ALT_CRS) geom = MatchCRS.geometry(geometry_urb, DEF_CRS, ALT_CRS) assert (abs(geom.centroid.x * 1e-4 - (-362.099)) < 1e-3 and abs(bbox[0] * 1e-4 - (-365.403)) < 1e-3 and abs(coords[0][-1] * 1e-4 == (-287.707)) < 1e-3)
def elevation_byloc(coord: Tuple[float, float], crs: str = DEF_CRS): """Get elevation from USGS 3DEP service for a coordinate. Parameters ---------- coord : tuple Coordinates of the location as a tuple crs : str, optional The spatial reference of the input coord, defaults to epsg:4326 (lon, lat) Returns ------- float Elevation in meter """ if not isinstance(coord, tuple) or len(coord) != 2: raise InvalidInputType("coord", "tuple of length 2", "(x, y)") lon, lat = MatchCRS.coords(([coord[0]], [coord[1]]), crs, DEF_CRS) url = "https://nationalmap.gov/epqs/pqs.php" payload = {"output": "json", "x": lon[0], "y": lat[0], "units": "Meters"} r = RetrySession().get(url, payload) root = r.json()["USGS_Elevation_Point_Query_Service"] elevation = float(root["Elevation_Query"]["Elevation"]) if abs(elevation - (-1000000)) < 1e-3: raise ValueError( f"The elevation of the requested coordinate ({coord[0]}, {coord[1]}) cannot be found." ) return elevation
def test_grid(geometry): geo_crs = DEF_CRS crs = "+proj=lcc +lat_1=25 +lat_2=60 +lat_0=42.5 +lon_0=-100 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs" geom = MatchCRS.geometry(geometry, geo_crs, crs) xmin, ymin, xmax, ymax = geom.bounds res = 1e3 gx = np.arange(xmin, xmax, res) gy = np.arange(ymin, ymax, res) elev = py3dep.elevation_bygrid(gx, gy, crs, res) assert abs(elev.mean().item() - 295.763) < 1e-3
def navigate_byloc( self, coords: Tuple[float, float], navigation: Optional[str] = None, source: Optional[str] = None, loc_crs: str = DEF_CRS, distance: int = 500, comid_only: bool = False, ) -> gpd.GeoDataFrame: """Navigate the NHDPlus databse from a coordinate. Parameters ---------- coordinate : tuple A tuple of length two (x, y). navigation : str, optional The navigation method, defaults to None which throws an exception if comid_only is False. source : str, optional Return the data from another source after navigating the features using fsource, defaults to None which throws an exception if comid_only is False. loc_crs : str, optional The spatial reference of the input coordinate, defaults to EPSG:4326. distance : int, optional Limit the search for navigation up to a distance in km, defaults to 500 km. Note that this is an expensive request so you have be mindful of the value that you provide. If you want to get all the available features you can pass a large distance like 9999999. comid_only : bool, optional Whether to return the nearest comid without navigation. Returns ------- geopandas.GeoDataFrame NLDI indexed features in EPSG:4326. """ _coords = MatchCRS().coords(((coords[0], ), (coords[1], )), loc_crs, DEF_CRS) lon, lat = _coords[0][0], _coords[1][0] url = "/".join([self.base_url, "linked-data", "comid", "position"]) payload = {"coords": f"POINT({lon} {lat})"} rjson = self._geturl(url, payload) comid = geoutils.json2geodf(rjson, ALT_CRS, DEF_CRS).comid.iloc[0] if comid_only: return comid if navigation is None or source is None: raise MissingItems(["navigation", "source"]) return self.navigate_byid("comid", comid, navigation, source, distance)
def bydistance(self, coords: Tuple[float, float], distance: int, loc_crs: str = DEF_CRS) -> gpd.GeoDataFrame: """Get features within a radius (in meters) of a point.""" if isinstance(coords, (list, tuple)) and len(coords) != 2: raise InvalidInputType("coords", "tuple or list of length 2.") _coords = MatchCRS.coords(((coords[0], ), (coords[1], )), loc_crs, ALT_CRS) cql_filter = ( f"DWITHIN(the_geom,POINT({_coords[1][0]:.6f} {_coords[0][0]:.6f}),{distance},meters)" ) resp = self.wfs.getfeature_byfilter(cql_filter, "GET") return self._to_geodf(resp)
def comid_byloc( self, coords: Union[Tuple[float, float], List[Tuple[float, float]]], loc_crs: str = DEF_CRS, ) -> Union[gpd.GeoDataFrame, Tuple[gpd.GeoDataFrame, List[Tuple[float, float]]]]: """Get the closest ComID(s) based on coordinates. Parameters ---------- coords : tuple or list A tuple of length two (x, y) or a list of them. loc_crs : str, optional The spatial reference of the input coordinate, defaults to EPSG:4326. Returns ------- geopandas.GeoDataFrame or (geopandas.GeoDataFrame, list) NLDI indexed ComID(s) in EPSG:4326. If some coords don't return any ComID a list of missing coords are returnd as well. """ coords = coords if isinstance(coords, list) else [coords] coords_4326 = list( zip(*MatchCRS.coords(tuple(zip(*coords)), loc_crs, DEF_CRS))) base_url = "/".join( [self.base_url, "linked-data", "comid", "position"]) urls = {(coords[i][0], coords[i][1]): f"{base_url}?coords=POINT({lon} {lat})" for i, (lon, lat) in enumerate(coords_4326)} comids, not_found = self._get_urls(urls) comids = comids.reset_index(level=2, drop=True) if len(not_found) > 0: self._missing_warning(len(not_found), len(coords)) return comids, not_found return comids
def elevation_bycoords(coords: List[Tuple[float, float]], crs: str = DEF_CRS) -> List[int]: """Get elevation from Airmap for a list of coordinates. Parameters ---------- coords : list of tuples Coordinates of the location as a tuple crs : str, optional The spatial reference of the input coord, defaults to epsg:4326 (lon, lat) Returns ------- list of int Elevation in meter """ if not isinstance(coords, (list, Iterator)): raise InvalidInputType("coord", "list (or iterator) of tuples of length 2", "[(x, y), ...]") if isinstance(coords, list) and any(len(c) != 2 for c in coords): raise InvalidInputType("coord", "list of tuples of length 2", "[(x, y), ...]") coords_reproj = zip(*MatchCRS.coords(tuple(zip(*coords)), crs, DEF_CRS)) coords_reproj = tlz.partition_all(100, coords_reproj) headers = {"Content-Type": "application/json", "charset": "utf-8"} elevations = [] for chunk in coords_reproj: payload = {"points": ",".join(f"{lat},{lon}" for lon, lat in chunk)} resp = RetrySession().get(ServiceURL().restful.airmap, payload=payload, headers=headers) elevations.append(resp.json()["data"]) return list(tlz.concat(elevations))
def get_byloc( coords: Tuple[float, float], dates: Union[Tuple[str, str], Union[int, List[int]]], crs: str = DEF_CRS, variables: Optional[Union[List[str], str]] = None, pet: bool = False, ) -> pd.DataFrame: """Get daily climate data from Daymet for a single point. Parameters ---------- coords : tuple Longitude and latitude of the location of interest as a tuple (lon, lat) dates : tuple or list Either a tuple (start, end) or a list of years [YYYY, ...]. crs : str, optional The spatial reference of the input coordinates, defaults to epsg:4326 variables : str or list or tuple, optional List of variables to be downloaded. The acceptable variables are: ``tmin``, ``tmax``, ``prcp``, ``srad``, ``vp``, ``swe``, ``dayl`` Descriptions can be found `here <https://daymet.ornl.gov/overview>`__. Defaults to None i.e., all the variables are downloaded. pet : bool, optional Whether to compute evapotranspiration based on `UN-FAO 56 paper <http://www.fao.org/docrep/X0490E/X0490E00.htm>`__. The default is False Returns ------- pandas.DataFrame Daily climate data for a location """ daymet = Daymet(variables, pet) if isinstance(dates, tuple) and len(dates) == 2: dates_dict = daymet.dates_todict(dates) elif isinstance(dates, (list, int)): dates_dict = daymet.years_todict(dates) else: raise InvalidInputType("dates", "tuple or list", "(start, end) or [2001, 2010, ...]") if isinstance(coords, tuple) and len(coords) == 2: _coords = MatchCRS.coords(((coords[0], ), (coords[1], )), crs, DEF_CRS) lon, lat = (_coords[0][0], _coords[1][0]) else: raise InvalidInputType("coords", "tuple", "(lon, lat)") if not ((14.5 < lat < 52.0) or (-131.0 < lon < -53.0)): raise InvalidInputRange( "The location is outside the Daymet dataset. " + "The acceptable range is: " + "14.5 < lat < 52.0 and -131.0 < lon < -53.0") payload = { "lat": f"{lat:.6f}", "lon": f"{lon:.6f}", "vars": ",".join(daymet.variables), "format": "json", **dates_dict, } r = daymet.session.get(ServiceURL().restful.daymet_point, payload) clm = pd.DataFrame(r.json()["data"]) clm.index = pd.to_datetime(clm.year * 1000.0 + clm.yday, format="%Y%j") clm = clm.drop(["year", "yday"], axis=1) if pet: clm = daymet.pet_byloc(clm, (lon, lat)) return clm