def getfeature_byid(self, fsource: str, fid: str, basin: bool = False) -> gpd.GeoDataFrame: """Get features of a single id. Parameters ---------- fsource : str The name of feature source. The valid sources are: comid, huc12pp, nwissite, wade, wqp fid : str The ID of the feature. basin : bool Whether to return the basin containing the feature. Returns ------- geopandas.GeoDataFrame NLDI indexed features in EPSG:4326. """ self._validate_fsource(fsource) url = "/".join([self.base_url, "linked-data", fsource, fid]) if basin: url += "/basin" return geoutils.json2geodf(self._geturl(url), ALT_CRS, DEF_CRS)
def _get_urls(self, urls: Dict[Any, str]) -> Tuple[gpd.GeoDataFrame, List[str]]: """Get basins for a list of station IDs. Parameters ---------- urls_dict : dict A dict with keys as feature ids and values as corresponsing url. Returns ------- (geopandas.GeoDataFrame, list) NLDI indexed features in EPSG:4326 and list of ID(s) that no feature was found. """ not_found = [] resp = [] for f, u in urls.items(): try: rjson = self._get_url(u) resp.append((f, geoutils.json2geodf(rjson, ALT_CRS, DEF_CRS))) except (ZeroMatched, JSONDecodeError, ConnectionError): not_found.append(f) if len(resp) == 0: raise ZeroMatched("No feature was found with the provided inputs.") resp_df = gpd.GeoDataFrame(pd.concat(dict(resp))) return resp_df, not_found
def get_json(self, endpoint: str, kwds: Dict[str, str], request_method: str = "GET") -> gpd.GeoDataFrame: """Get the JSON response from the Water Quality Web Service. Parameters ---------- endpoint : str Endpoint of the Water Quality Web Service. kwds : dict Water Quality Web Service keyword arguments. request_method : str, optional HTTP request method. Default to GET. Returns ------- geopandas.GeoDataFrame The web service response as a GeoDataFrame. """ req_kwds = [{ "params": kwds }] if request_method == "GET" else [{ "data": kwds }] return geoutils.json2geodf( ar.retrieve_json( [self._base_url(endpoint)], req_kwds, request_method=request_method, expire_after=self.expire_after, disable=self.disable_caching, ))
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 navigate_byid( self, fsource: str, fid: str, navigation: str, source: str, distance: int = 500, ) -> gpd.GeoDataFrame: """Navigate the NHDPlus databse from a single feature id up to a distance. Parameters ---------- fsource : str The name of feature source. The valid sources are: comid, huc12pp, nwissite, wade, WQP. fid : str The ID of the feature. navigation : str The navigation method. source : str, optional Return the data from another source after navigating the features using fsource, defaults to None. distance : int, optional Limit the search for navigation up to a distance in km, defaults is 500 km. Note that this is an expensive request so you have be mindful of the value that you provide. Returns ------- geopandas.GeoDataFrame NLDI indexed features in EPSG:4326. """ self._validate_fsource(fsource) url = "/".join( [self.base_url, "linked-data", fsource, fid, "navigation"]) valid_navigations = self._get_url(url) if navigation not in valid_navigations.keys(): raise InvalidInputValue("navigation", list(valid_navigations.keys())) url = valid_navigations[navigation] r_json = self._get_url(url) valid_sources = {s["source"].lower(): s["features"] for s in r_json} # type: ignore if source not in valid_sources: raise InvalidInputValue("source", list(valid_sources.keys())) url = f"{valid_sources[source]}?distance={int(distance)}" return geoutils.json2geodf(self._get_url(url), ALT_CRS, DEF_CRS)
def to_geodf(self, resp: Response) -> gpd.GeoDataFrame: """Convert a response from WaterData to a GeoDataFrame. Parameters ---------- resp : Response A response from a WaterData request. Returns ------- geopandas.GeoDataFrame The requested features in a GeoDataFrames. """ return geoutils.json2geodf(resp.json(), ALT_CRS, self.crs)
def _getfeatures(self, return_m: bool = False): """Send a request for getting data based on object IDs. Parameters ---------- return_m : bool Whether to activate the Return M (measure) in the request, defaults to False. Returns ------- geopandas.GeoDataFrame The requested features as a GeoDataFrame. """ resp = self.service.get_features(return_m) return geoutils.json2geodf(resp)
def test_json2geodf(geometry_urb): url_wfs = "https://hazards.fema.gov/gis/nfhl/services/public/NFHL/MapServer/WFSServer" wfs = WFS( url_wfs, layer="public_NFHL:Base_Flood_Elevations", outformat="esrigeojson", crs="epsg:4269", version="2.0.0", ) bbox = geometry_urb.bounds r = wfs.getfeature_bybox(bbox, box_crs=DEF_CRS) flood = geoutils.json2geodf([r.json(), r.json()], "epsg:4269", DEF_CRS) flood = flood.drop_duplicates() assert abs(flood["ELEV"].sum() - 631366.6) < 1e-1