Source code for watershed_workflow.sources.manager_wbd
from typing import List, Optional
import logging
import geopandas as gpd
import watershed_workflow.crs
from . import standard_names as names
from . import manager_hyriver
[docs]
class ManagerWBD(manager_hyriver.ManagerHyRiver):
"""Leverages pygeohydro to download WBD data."""
lowest_level = 12
def __init__(self, protocol_name : str = 'WBD'):
"""Also valid is WaterData"""
self._level : Optional[int] = None
# WBD data is typically in lat/lon coordinates
native_crs_in = watershed_workflow.crs.from_epsg(4269)
native_resolution = 0.001 # ~100m at mid-latitudes
super().__init__(protocol_name, native_crs_in, native_resolution)
self.name = 'WBD'
def set(self, **kwargs):
if 'level' in kwargs:
self.setLevel(kwargs['level'])
def setLevel(self, level : int) -> None:
self._level = level
if self._protocol_name == 'WBD':
self._layer = f'huc{level}'
self._id_name = self._layer
else:
self._layer = f'wbd{level:02d}'
self._id_name = f'huc{level}'
def _getShapesByID(self,
hucs : List[str]) -> gpd.GeoDataFrame:
"""Finds all HUs in the WBD dataset of a given level contained in a list of HUCs."""
req_levels = set(len(l) for l in hucs)
if len(req_levels) != 1:
raise ValueError("ManagerWBD.getShapesByID can only be called with a list of HUCs of the same level")
req_level = req_levels.pop()
if self._level is not None and self._level != req_level:
level = self._level
self.setLevel(req_level)
geom_df = self._getShapesByID(hucs)
self.setLevel(level)
df = self.getShapesByGeometry(geom_df.union_all(), geom_df.crs, geom_df.crs)
return df[df.ID.apply(lambda l : any(l.startswith(huc) for huc in hucs))]
else:
self.setLevel(req_level)
df = super()._getShapesByID(hucs)
return df
def _addStandardNames(self, df: gpd.GeoDataFrame) -> gpd.GeoDataFrame:
"""Convert native column names to standard names.
Parameters
----------
df : gpd.GeoDataFrame
GeoDataFrame with native column names.
Returns
-------
gpd.GeoDataFrame
GeoDataFrame with standard column names added.
"""
# Add ID column from current ID field (set by setLevel)
if hasattr(self, '_id_name') and self._id_name in df.columns:
df[names.ID] = df[self._id_name].astype('string')
# Add WBD-specific standard name mappings
if 'areasqkm' in df.columns:
df[names.AREA] = df['areasqkm']
# Add HUC field if level is set
if self._level is not None:
huc_field = f'huc{self._level}'
if huc_field in df.columns:
df[names.HUC] = df[huc_field]
return df
[docs]
def getAll(self,
level : int) -> gpd.GeoDataFrame:
"""Download all HUCs at a given level."""
# this is a shortcut...
import pygeohydro.watershed
df = pygeohydro.watershed.huc_wb_full(level)
df[names.HUC] = df[f'huc{level}']
df[names.AREA] = df[f'areasqkm']
return df