def get_hucs(self, huc, level): """Loads HUCs from file.""" huc = source_utils.huc_str(huc) huc_level = len(huc) # error checking on the levels, require file_level <= huc_level <= level <= lowest_level if self.lowest_level < level: raise ValueError("{}: files include HUs at max level {}.".format( self.name, self.lowest_level)) if level < huc_level: raise ValueError( "{}: cannot ask for HUs at level {} contained in {}.".format( self.name, level, huc_level)) if huc_level < self.file_level: raise ValueError( "{}: files are organized at HUC level {}, so cannot ask for a larger HUC than that level." .format(self.name, self.file_level)) # download the file filename = self._download(huc[0:self.file_level]) logging.info('Using HUC file "{}"'.format(filename)) # read the file layer = 'WBDHU{}'.format(level) logging.debug("{}: opening '{}' layer '{}' for HUCs in '{}'".format( self.name, filename, layer, huc)) with fiona.open(filename, mode='r', layer=layer) as fid: hus = [ hu for hu in fid if hu['properties']['HUC{:d}'.format(level)].startswith(huc) ] profile = fid.profile return profile, hus
def get_hydro(self, huc, bounds=None, bounds_crs=None): """Get all reaches within a given HUC and/or coordinate bounds. Parameters ---------- huc : int or str The USGS Hydrologic Unit Code bounds : [xmin, ymin, xmax, ymax], optional Coordinate bounds to filter reaches returned. If this is provided, bounds_crs must also be provided. bounds_crs : CRS, optional CRS of the above bounds. Returns ------- profile : dict The fiona shapefile profile (see Fiona documentation). reaches : list(dict) List of fiona shape objects representing the stream reaches. Note this finds and downloads files as needed. """ if 'WBD' in self.name: raise RuntimeError( '{}: does not provide hydrographic data.'.format(self.name)) huc = source_utils.huc_str(huc) hint_level = len(huc) # try to get bounds if not provided if bounds is None: # can we infer a bounds by getting the HUC? profile, hu = self.get_huc(huc) bounds = workflow.utils.bounds(hu) bounds_crs = workflow.crs.from_fiona(profile['crs']) # error checking on the levels, require file_level <= huc_level <= lowest_level if hint_level < self.file_level: raise ValueError( "{}: files are organized at HUC level {}, so cannot ask for a larger HUC than that level." .format(self.name, self.file_level)) # download the file filename = self._download(huc[0:self.file_level]) logging.info('Using Hydrography file "{}"'.format(filename)) # find and open the hydrography layer filename = self.name_manager.file_name(huc[0:self.file_level]) layer = 'NHDFlowline' logging.debug("{}: opening '{}' layer '{}' for streams in '{}'".format( self.name, filename, layer, bounds)) with fiona.open(filename, mode='r', layer=layer) as fid: profile = fid.profile bounds = workflow.warp.bounds( bounds, bounds_crs, workflow.crs.from_fiona(profile['crs'])) rivers = [r for (i, r) in fid.items(bbox=bounds)] return profile, rivers
def get_hucs(self, huc, level, force_download=False): """Get all sub-catchments of a given HUC level within a given HUC. Parameters ---------- huc : int or str The USGS Hydrologic Unit Code level : int Level of requested sub-catchments. Must be larger or equal to the level of the input huc. force_download : bool Download or re-download the file if true. Returns ------- profile : dict The fiona shapefile profile (see Fiona documentation). hus : list(dict) List of fiona shape objects representing the hydrologic units. Note this finds and downloads files as needed. """ huc = source_utils.huc_str(huc) huc_level = len(huc) # error checking on the levels, require file_level <= huc_level <= level <= lowest_level if self.lowest_level < level: raise ValueError("{}: files include HUs at max level {}.".format( self.name, self.lowest_level)) if level < huc_level: raise ValueError( "{}: cannot ask for HUs at level {} contained in {}.".format( self.name, level, huc_level)) if huc_level < self.file_level: raise ValueError( "{}: files are organized at HUC level {}, so cannot ask for a larger HUC than that level." .format(self.name, self.file_level)) # download the file filename = self._download(huc[0:self.file_level], force=force_download) logging.info('Using HUC file "{}"'.format(filename)) # read the file layer = 'WBDHU{}'.format(level) logging.debug("{}: opening '{}' layer '{}' for HUCs in '{}'".format( self.name, filename, layer, huc)) with fiona.open(filename, mode='r', layer=layer) as fid: hus = [ hu for hu in fid if source_utils.get_code(hu, level).startswith(huc) ] profile = fid.profile profile['always_xy'] = True return profile, hus
def get_hucs(self, huc, level): huc = source_utils.huc_str(huc) if len(huc) > 2: return self.nhd_plus.get_hucs(huc, level) else: prof, wbd_hucs = self.wbd.get_hucs(huc, 4) contained = [] for hu in wbd_hucs: print(list(hu['properties'].keys())) prof, subhucs = self.nhd_plus.get_hucs(hu['properties']['HUC4'], level) contained.extend(subhucs) return prof, contained
def get_huc(self, huc, force_download=False): """Get the specified HUC in its native CRS. Parameters ---------- huc : int or str The USGS Hydrologic Unit Code Returns ------- profile : dict The fiona shapefile profile (see Fiona documentation). hu : dict Fiona shape object representing the hydrologic unit. Note this finds and downloads files as needed. """ huc = source_utils.huc_str(huc) profile, hus = self.get_hucs(huc, len(huc), force_download) assert (len(hus) == 1) return profile, hus[0]
def get_hydro(self, huc, bounds=None, bounds_crs=None): """Downloads and reads hydrography within these bounds and/or huc. Note this requires a HUC hint of at least a level 4 HUC which contains bounds. """ if 'WBD' in self.name: raise RuntimeError( '{}: does not provide hydrographic data.'.format(self.name)) huc = source_utils.huc_str(huc) hint_level = len(huc) # try to get bounds if not provided if bounds is None: # can we infer a bounds by getting the HUC? profile, hu = self.get_huc(huc) bounds = workflow.utils.bounds(hu) bounds_crs = profile['crs'] # error checking on the levels, require file_level <= huc_level <= lowest_level if hint_level < self.file_level: raise ValueError( "{}: files are organized at HUC level {}, so cannot ask for a larger HUC than that level." .format(self.name, self.file_level)) # download the file filename = self._download(huc[0:self.file_level]) logging.info('Using Hydrography file "{}"'.format(filename)) # find and open the hydrography layer filename = self.name_manager.file_name(huc[0:self.file_level]) layer = 'NHDFlowline' logging.debug("{}: opening '{}' layer '{}' for streams in '{}'".format( self.name, filename, layer, bounds)) with fiona.open(filename, mode='r', layer=layer) as fid: profile = fid.profile bounds = workflow.warp.warp_bounds(bounds, bounds_crs, profile['crs']) rivers = [r for (i, r) in fid.items(bbox=bounds)] return profile, rivers
def get_huc(self, huc): huc = source_utils.huc_str(huc) profile, hus = self.get_hucs(huc, len(huc)) assert (len(hus) == 1) return profile, hus[0]
def get_huc(self, huc): huc = source_utils.huc_str(huc) if len(huc) > 2: return self.nhd_plus.get_huc(huc) else: return self.wbd.get_huc(huc)
def get_hydro(self, huc, bounds=None, bounds_crs=None, in_network=True, force_download=False): """Get all reaches within a given HUC and/or coordinate bounds. Parameters ---------- huc : int or str The USGS Hydrologic Unit Code bounds : [xmin, ymin, xmax, ymax], optional Coordinate bounds to filter reaches returned. If this is provided, bounds_crs must also be provided. bounds_crs : CRS, optional CRS of the above bounds. in_network : bool, optional If True (default), remove reaches that are not "in" the NHD network force_download : bool Download or re-download the file if true. Returns ------- profile : dict The fiona shapefile profile (see Fiona documentation). reaches : list(dict) List of fiona shape objects representing the stream reaches. Note this finds and downloads files as needed. """ if 'WBD' in self.name: raise RuntimeError( '{}: does not provide hydrographic data.'.format(self.name)) huc = source_utils.huc_str(huc) hint_level = len(huc) # try to get bounds if not provided if bounds is None: # can we infer a bounds by getting the HUC? profile, hu = self.get_huc(huc) bounds = workflow.utils.bounds(hu) bounds_crs = workflow.crs.from_fiona(profile['crs']) # error checking on the levels, require file_level <= huc_level <= lowest_level if hint_level < self.file_level: raise ValueError( "{}: files are organized at HUC level {}, so cannot ask for a larger HUC than that level." .format(self.name, self.file_level)) # download the file filename = self._download(huc[0:self.file_level], force=force_download) logging.info(' Using Hydrography file "{}"'.format(filename)) # find and open the hydrography layer filename = self.name_manager.file_name(huc[0:self.file_level]) layer = 'NHDFlowline' logging.info( " {}: opening '{}' layer '{}' for streams in '{}'".format( self.name, filename, layer, bounds)) with fiona.open(filename, mode='r', layer=layer) as fid: profile = fid.profile bounds = workflow.warp.bounds( bounds, bounds_crs, workflow.crs.from_fiona(profile['crs'])) reaches = [r for (i, r) in fid.items(bbox=bounds)] # filter not in network if in_network: logging.info(" Filtering reaches not in-network".format( self.name, filename, layer, bounds)) reaches = [ r for r in reaches if 'InNetwork' not in r['properties'] or r['properties']['InNetwork'] == 1 ] # associate catchment areas with the reaches if NHDPlus if 'Plus' in self.name: layer = 'NHDPlusCatchment' logging.info( " {}: opening '{}' layer '{}' for catchment areas in '{}'". format(self.name, filename, layer, bounds)) with fiona.open(filename, mode='r', layer=layer) as fid: bounded_catchments = list(fid.items()) #.items(bbox=bounds)) missing_catchments = 0 for i, reach in enumerate(reaches): try: catch = next(c for (i, c) in bounded_catchments if c['properties']['NHDPlusID'] == reach['properties']['NHDPlusID']) except StopIteration: logging.debug( f"reach missing catchment: {reach['properties']['NHDPlusID']}" ) if missing_catchments == i and missing_catchments > 10: # give up fairly quickly, as this can be slow break missing_catchments += 1 else: reach['properties']['catchment'] = catch return profile, reaches