def add_id_range_data_to_grid(iso3, tile_lookup, side_length): """ Query the Digital Elevation Model to get an estimated interdecile range for each grid square. """ directory = os.path.join(DATA_INTERMEDIATE, iso3, 'grid') filename = 'grid_final.shp' path_output = os.path.join(directory, filename) if os.path.exists(path_output): return gpd.read_file(path_output, crs='epsg:4328') filename = 'grid_{}_{}_km.shp'.format(side_length, side_length) path = os.path.join(directory, filename) grid = gpd.read_file(path, crs='epsg:4328') output = [] for idx, grid_tile in grid.iterrows(): path_input = find_tile( grid_tile['geometry'].bounds, tile_lookup ) stats = next(gen_zonal_stats( grid_tile['geometry'], path_input, add_stats={ 'interdecile_range': interdecile_range }, nodata=0 )) id_range_m = stats['interdecile_range'] output.append({ 'type': 'Feature', 'geometry': grid_tile['geometry'], 'properties': { 'id_range_m': id_range_m, 'area_km2': grid_tile['area_km2'], # 'pop_density_km2': grid_tile['pop_densit'], # 'population': grid_tile['population'], } }) output = gpd.GeoDataFrame.from_features(output, crs='epsg:4326') output = output.replace([np.inf, -np.inf], np.nan) output = output[output.geometry.notnull()] output.to_file(path_output, crs="epsg:4326") return output
def zonalstats(features, raster, all_touched, band, categorical, indent, info, nodata, prefix, stats, sequence, use_rs): '''zonalstats generates summary statistics of geospatial raster datasets based on vector features. The input arguments to zonalstats should be valid GeoJSON Features. (see cligj) The output GeoJSON will be mostly unchanged but have additional properties per feature describing the summary statistics (min, max, mean, etc.) of the underlying raster dataset. The raster is specified by the required -r/--raster argument. Example, calculate rainfall stats for each state and output to file: \b rio zonalstats states.geojson -r rainfall.tif > mean_rainfall_by_state.geojson ''' if info: logging.basicConfig(level=logging.INFO) if stats is not None: stats = stats.split(" ") if 'all' in [x.lower() for x in stats]: stats = "ALL" zonal_results = gen_zonal_stats(features, raster, all_touched=all_touched, band_num=band, categorical=categorical, nodata=nodata, stats=stats, prefix=prefix, geojson_out=True) if sequence: for feature in zonal_results: if use_rs: click.echo(b'\x1e', nl=False) click.echo(json.dumps(feature)) else: click.echo( json.dumps({ 'type': 'FeatureCollection', 'features': list(zonal_results) }))
def zonalstats(features, raster, all_touched, band, categorical, indent, info, nodata, prefix, stats, sequence, use_rs): '''zonalstats generates summary statistics of geospatial raster datasets based on vector features. The input arguments to zonalstats should be valid GeoJSON Features. (see cligj) The output GeoJSON will be mostly unchanged but have additional properties per feature describing the summary statistics (min, max, mean, etc.) of the underlying raster dataset. The raster is specified by the required -r/--raster argument. Example, calculate rainfall stats for each state and output to file: \b rio zonalstats states.geojson -r rainfall.tif > mean_rainfall_by_state.geojson ''' if info: logging.basicConfig(level=logging.INFO) if stats is not None: stats = stats.split(" ") if 'all' in [x.lower() for x in stats]: stats = "ALL" zonal_results = gen_zonal_stats( features, raster, all_touched=all_touched, band=band, categorical=categorical, nodata=nodata, stats=stats, prefix=prefix, geojson_out=True) if sequence: for feature in zonal_results: if use_rs: click.echo(b'\x1e', nl=False) click.echo(json.dumps(feature)) else: click.echo(json.dumps( {'type': 'FeatureCollection', 'features': list(zonal_results)}))
def terrain_area(dem, lon, lat, cell_range): """ This module takes a single set of point coordinates for a site along with an estimate of the cell range. The irregular terrain parameter is returned. Parameters ---------- dem : str Path to the available Digital Elevation Model as single raster file or vrt. lon : float Longitude of cell point lat : float Latitude of cell point cell_range : int Radius of cell area in meters. Returns ------- Inter-decile range : int The terrain irregularity parameter. """ # Buffer around cell point cell_area = geodesic_point_buffer(lon, lat, cell_range) # Calculate raster stats stats = next(gen_zonal_stats( [cell_area], dem, add_stats={ 'interdecile_range': interdecile_range }, nodata=-9999 )) id_range = stats['interdecile_range'] return id_range
def check_foliage_presence(routing_structure, modis_lookup): """ Check for potential foliage. """ geom = shape(routing_structure['geometry']) routing_structure = gpd.GeoDataFrame({'geometry': [geom]}, index=[0], crs='epsg:3857') routing_structure['geometry'] = routing_structure['geometry'].to_crs( 'epsg:4326') representative_point = routing_structure['geometry'].representative_point( )[0] tile_paths = find_correct_tile(representative_point, modis_lookup) results = [] for tile_path in tile_paths: stats = next( gen_zonal_stats(routing_structure['geometry'], tile_path, nodata=-9999)) if not stats['mean'] == None: results.append(stats['mean']) mean = sum(results) / len(results) if mean < 20: return 'nofoliage' elif mean >= 20: return 'foliage' else: print('Did not recognize zonal stats result')
def get_data(iso3, tile_lookup): """ """ output = [] path = os.path.join(DATA_INTERMEDIATE, iso3, 'gid_3_regional_data.csv') if os.path.exists(path): return path_settlements = os.path.join(DATA_INTERMEDIATE, iso3, 'settlements.tif') filename = 'regions_3_{}.shp'.format(iso3) path = os.path.join(DATA_INTERMEDIATE, iso3, 'regions', filename) regions = gpd.read_file(path, crs='epsg:4326') #[:1] for idx, region in regions.iterrows(): area_km2 = get_area(region) path_input = find_correct_raster_tile(region['geometry'].bounds, tile_lookup) stats = next( gen_zonal_stats(region['geometry'], path_input, add_stats={'interdecile_range': interdecile_range}, nodata=0)) id_range_m = stats['interdecile_range'] with rasterio.open(path_settlements) as src: affine = src.transform array = src.read(1) array[array <= 0] = 0 population = [ d['sum'] for d in zonal_stats(region['geometry'], array, stats=['sum'], nodata=0, affine=affine) ][0] if not population == None: if population > 0: pop_density_km2 = population / area_km2 else: pop_density_km2 = 0 else: population = 0 pop_density_km2 = 0 output.append({ 'GID_0': region['GID_0'], 'GID_2': region['GID_2'], 'GID_3': region['GID_3'], 'population': population, 'area_km2': area_km2, 'pop_density_km2': pop_density_km2, 'id_range_m': id_range_m, }) output = pd.DataFrame(output) output.to_csv(path, index=False) return
def create_pop_and_terrain_regional_lookup(country): """ Extract regional luminosity and population data. Parameters ---------- country : dict Contains all country-specific information for modeling. """ iso3 = country['iso3'] path_settlements = os.path.join(DATA_INTERMEDIATE, iso3, 'settlements.tif') filename = 'modeling_regions.shp' path = os.path.join(DATA_INTERMEDIATE, iso3, 'modeling_regions', filename) modeling_regions = gpd.read_file(path, crs='epsg:4326') #[:5] filename = 'main_nodes.shp' path = os.path.join(DATA_INTERMEDIATE, iso3, 'network_routing_structure', filename) main_nodes = gpd.read_file(path, crs='epsg:4326') #[:5] tile_lookup = load_raster_tile_lookup(country) output = [] for index, modeling_region in modeling_regions.iterrows(): # if not modeling_region['regions'] == 'PER.15.1_1': # continue area_km2 = get_area(modeling_region) path_input = find_correct_raster_tile( modeling_region['geometry'].bounds, tile_lookup) stats = next( gen_zonal_stats(modeling_region['geometry'], path_input, add_stats={'interdecile_range': interdecile_range}, nodata=0)) id_range_m = stats['interdecile_range'] with rasterio.open(path_settlements) as src: affine = src.transform array = src.read(1) array[array <= 0] = 0 population = [ d['sum'] for d in zonal_stats(modeling_region['geometry'], array, stats=['sum'], nodata=0, affine=affine) ][0] if not population == None: if population > 0: pop_density_km2 = population / area_km2 else: pop_density_km2 = 0 else: population = 0 pop_density_km2 = 0 if modeling_region['geometry'].type == 'Polygon': region_geom = gpd.GeoDataFrame( {'geometry': modeling_region['geometry']}, index=[0], crs='epsg:4326') else: region_geom = gpd.GeoDataFrame( {'geometry': modeling_region['geometry']}, crs='epsg:4326') main_node = gpd.overlay(main_nodes, region_geom, how='intersection') if len(main_node) == 0: continue modeling_region_id = main_node['GID_{}'.format( country['regional_level'])].values[0] output.append({ 'modeling_region': modeling_region_id, 'regions': modeling_region['regions'], 'names': modeling_region['names'], 'id_range_m': id_range_m, 'population': population, 'area_km2': area_km2, 'pop_density_km2': pop_density_km2, }) output = pd.DataFrame(output) filename = 'population_and_terrain_lookup.csv' path = os.path.join(DATA_INTERMEDIATE, iso3, filename) output.to_csv(path, index=False) return print('Completed population and terrain lookup')
def create_pop_and_terrain_regional_lookup(country): """ Extract regional luminosity and population data. Parameters ---------- country : dict Contains all country-specific information for modeling. """ iso3 = country['iso3'] filename = 'ppp_2020_1km_Aggregated.tif' path_settlements = os.path.join(DATA_RAW, 'settlement_layer', filename) filename = 'modeling_regions.shp' path = os.path.join(DATA_INTERMEDIATE, iso3, 'modeling_regions', filename) modeling_regions = gpd.read_file(path, crs='epsg:4326')#[:5] tile_lookup = load_raster_tile_lookup(country) output = [] for index, modeling_region in modeling_regions.iterrows(): # if not modeling_region['regions'] == 'PER.15.1_1': # continue area_km = get_area(modeling_region) path_input = find_correct_raster_tile(modeling_region['geometry'].bounds, tile_lookup) stats = next(gen_zonal_stats( modeling_region['geometry'], path_input, add_stats={ 'interdecile_range': interdecile_range }, nodata=0 )) id_range_m = stats['interdecile_range'] with rasterio.open(path_settlements) as src: affine = src.transform array = src.read(1) array[array <= 0] = 0 population = [d['sum'] for d in zonal_stats( modeling_region['geometry'], array, stats=['sum'], nodata=0, affine=affine )][0] if population > 0: pop_density_km2 = population / area_km else: pop_density_km2 = 0 output.append({ 'regions': modeling_region['regions'], 'id_range_m': id_range_m, 'population': population, 'area_m': area_km, 'pop_density_km2': pop_density_km2, }) output = pd.DataFrame(output) filename = 'population_and_terrain_lookup.csv' path = os.path.join(DATA_INTERMEDIATE, iso3, filename) output.to_csv(path, index=False) return print('Completed population and terrain lookup')