3DEP Elevation Grid-to-line intersection#
Introduction#
In this example, a set of target NHD stream-segments is developed using the HyRiver package. A USGS 3DEP Elevation dataset is pulled using the ClimateR-Catalog. Finally gdptools InterpGen class is used to interpolate both the stream-segments and then interpolate elevatoin from the 3DEP dataset onto those points.
Create conda environment#
gdptools-examples can be downloaded from https://code.usgs.gov/wma/nhgf/toolsteam/gdptools/-/raw/develop/environment-examples.yml?inline=false
Imports#
import warnings
warnings.filterwarnings("ignore")
import geopandas as gpd
import pandas as pd
import hvplot.pandas
import hvplot.xarray
import xarray as xr
import pynhd
from pynhd import NLDI, NHDPlusHR, WaterData
from gdptools import UserTiffData
from gdptools import InterpGen
import geoviews as gv
gv.extension('bokeh', 'matplotlib')
# gv.extension()
# gv.output(dpi=120, fig='png')
# gv.output(backend='bokeh')
Create target lines#
nldi = NLDI()
station_id = "06730200"
basin = nldi.get_basins(station_id)
flw_main = nldi.navigate_byid(
fsource="nwissite",
fid=f"USGS-{station_id}",
navigation="upstreamMain",
source="flowlines",
distance=1000,
)
nhdp_mr = WaterData("nhdflowline_network")
comids = [int(c) for c in flw_main.nhdplus_comid.to_list()]
nhd_mr_fl = nhdp_mr.byid("comid", comids)
nhd_mr_fl.columns.to_list()
flw = pynhd.prepare_nhdplus(nhd_mr_fl, 0, 0, purge_non_dendritic=True)
flw2 = flw.rename(columns={"comid": "ID", "tocomid": "toID"})
strm_segs = pynhd.topoogical_sort(flw2)
# copy the sorted comids into a list and remove the last element
# List will be used to sort ouput into topological order later
sort_ids = strm_segs[0]
# create a new dataframe with the sorted comids
mr_fl = nhd_mr_fl.set_index("comid").loc[sort_ids[:-1]]
mr_fl = mr_fl.reset_index()
mr_fl.head()
comid | geometry | fdate | resolution | gnis_id | gnis_name | lengthkm | reachcode | flowdir | wbareacomi | ... | qc_12 | vc_12 | qe_12 | ve_12 | lakefract | surfarea | rareahload | rpuid | vpuid | enabled | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2889852 | MULTILINESTRING Z ((-105.63211 40.05203 0.0000... | 2000-12-22T05:00:00Z | Medium | 178467 | North Boulder Creek | 0.373 | 10190005000122 | With Digitized | 2888392 | ... | 0.376 | -9998.00000 | 0.376 | -9998.00000 | 1.0 | 50667.042715 | 10.004544 | 10c | 10L | 1 |
1 | 2889186 | MULTILINESTRING Z ((-105.62824 40.05363 0.0000... | 1999-05-28T04:00:00Z | Medium | 178467 | North Boulder Creek | 0.552 | 10190005000121 | With Digitized | 0 | ... | 0.498 | 0.57306 | 0.498 | 0.57306 | NaN | NaN | NaN | 10c | 10L | 1 |
2 | 2889770 | MULTILINESTRING Z ((-105.62207 40.05389 0.0000... | 1999-05-28T04:00:00Z | Medium | 178467 | North Boulder Creek | 0.478 | 10190005000120 | With Digitized | 2888388 | ... | 0.592 | -9998.00000 | 0.592 | -9998.00000 | 1.0 | 52090.136727 | 6.691098 | 10c | 10L | 1 |
3 | 2889188 | MULTILINESTRING Z ((-105.61719 40.05555 0.0000... | 1999-05-28T04:00:00Z | Medium | 178467 | North Boulder Creek | 0.396 | 10190005000119 | With Digitized | 0 | ... | 0.659 | 0.62836 | 0.659 | 0.62836 | NaN | NaN | NaN | 10c | 10L | 1 |
4 | 2889772 | MULTILINESTRING Z ((-105.61573 40.05258 0.0000... | 1999-05-28T04:00:00Z | Medium | 178467 | North Boulder Creek | 0.257 | 10190005000118 | With Digitized | 2888396 | ... | 0.785 | -9998.00000 | 0.785 | -9998.00000 | 1.0 | 48345.911611 | 4.708286 | 10c | 10L | 1 |
5 rows × 138 columns
Plot the target lines#
from bokeh.models import PrintfTickFormatter
formatter = PrintfTickFormatter(format="%i")
gv.tile_sources.EsriTerrain * gv.Path(mr_fl.to_crs(4326), vdims="comid").opts(color='comid',cmap='category20', width=600, height=300, aspect="equal", line_width=5, show_legend=True, colorbar=True, colorbar_opts={'formatter': formatter}, clabel="segment ID", title="NHDPlus MR Flowlines upstream of USGS Gage 06730200")
Define source data#
import pprint
climater_cat = "https://mikejohnson51.github.io/climateR-catalogs/catalog.parquet"
cat = pd.read_parquet(climater_cat)
_id = "USGS 3DEP"
_asset = "10m CONUS DEM"
_vars = ["elevation"]
# create list of catalog parameters for each variable
cat_params = [
cat.query("id == @_id & asset == @_asset & variable == @_vars").to_dict(orient="records")[0]
for _var in _vars
]
# create dictionary of variable names and catalog parameters
cat_dict = dict(zip(_vars, cat_params))
pprint.pprint(cat_dict)
{'elevation': {'T_name': None,
'URL': '/vsicurl/https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/13/TIFF/USGS_Seamless_DEM_13.vrt',
'X1': -180.0005555560936,
'X_name': None,
'Xn': 180.00000026239937,
'Y1': -180.0005555560936,
'Y_name': None,
'Yn': 72.0005555562949,
'asset': '10m CONUS DEM',
'crs': '+proj=longlat +datum=NAD83 +no_defs',
'description': '10m CONUS DEM',
'duration': None,
'ensemble': None,
'id': 'USGS 3DEP',
'interval': None,
'model': None,
'nT': nan,
'ncols': 3888006.0,
'nrows': 939612.0,
'resX': 9.259259266022042e-05,
'resY': 9.25925926599094e-05,
'scenario': None,
'tiled': '',
'toptobottom': None,
'type': 'vrt',
'units': 'meters',
'variable': 'elevation',
'varname': 'elevation'}}
Load source data#
import rioxarray as rxr
ds_3dep = rxr.open_rasterio(cat_dict["elevation"]["URL"])
ds_3dep
<xarray.DataArray (band: 1, y: 939612, x: 3888006)> [3653217093672 values with dtype=float32] Coordinates: * band (band) int64 1 * x (x) float64 -180.0 -180.0 -180.0 -180.0 ... 180.0 180.0 180.0 * y (y) float64 72.0 72.0 72.0 72.0 ... -15.0 -15.0 -15.0 -15.0 spatial_ref int64 0 Attributes: _FillValue: -999999.0 scale_factor: 1.0 add_offset: 0.0
Define UserTiffData
object#
varname = "elevation"
tx_name = "x"
ty_name = "y"
band = 1
bandname = "band"
crs = 4269
f_crs = 4326
id_feature = "comid"
user_data = UserTiffData(
var=varname,
ds=ds_3dep,
proj_ds=crs,
x_coord=tx_name,
y_coord=ty_name,
band=band,
bname=bandname,
f_feature=mr_fl,
id_feature=id_feature,
proj_feature=crs
)
Define InterpGen
object and generate interpolation#
interpObject1 = InterpGen(user_data, pt_spacing=100, stat='all', interp_method="linear")
# stats1, pts1 = interpObject1.calc_interp()
stats1, pts1 = interpObject1.calc_interp()
Plot the sub-setted 3DEP 10m DEM#
ds_ss = user_data.get_source_subset(key="").to_dataset(name="elevation")
ds_ss.elevation.hvplot.quadmesh(x="x", y="y", geo=True, project=True, rasterize=True, cmap="viridis", width=600, height=300, aspect="equal", clabel="3DEP 10m DEM", xlabel="Longitude", ylabel="Latitude", title="3DEP 10m DEM")
Show the interpolated points#
pts1.head(10)
band | spatial_ref | values | dist | comid | geometry | varname | |
---|---|---|---|---|---|---|---|
pt | |||||||
0 | 1 | 0 | 3620.148240 | 0.0 | 2889186 | POINT (-105.62824 40.05363) | elevation |
1 | 1 | 0 | 3620.536627 | 100.0 | 2889186 | POINT (-105.62721 40.05347) | elevation |
2 | 1 | 0 | 3605.426680 | 200.0 | 2889186 | POINT (-105.62617 40.05330) | elevation |
3 | 1 | 0 | 3589.268640 | 300.0 | 2889186 | POINT (-105.62513 40.05317) | elevation |
4 | 1 | 0 | 3578.737563 | 400.0 | 2889186 | POINT (-105.62408 40.05319) | elevation |
5 | 1 | 0 | 3571.558674 | 500.0 | 2889186 | POINT (-105.62307 40.05350) | elevation |
6 | 1 | 0 | 3561.002174 | 600.0 | 2889186 | POINT (-105.62208 40.05386) | elevation |
0 | 1 | 0 | 3562.425944 | 0.0 | 2889188 | POINT (-105.61719 40.05555) | elevation |
1 | 1 | 0 | 3560.132308 | 100.0 | 2889188 | POINT (-105.61623 40.05523) | elevation |
2 | 1 | 0 | 3524.454447 | 200.0 | 2889188 | POINT (-105.61593 40.05429) | elevation |
Show The statistics#
stats1.head(10)
comid | varname | mean | median | std | min | max | |
---|---|---|---|---|---|---|---|
0 | 2889186 | elevation | 3592.382657 | 3589.268640 | 21.869675 | 3561.002174 | 3620.536627 |
0 | 2889188 | elevation | 3530.434489 | 3542.293378 | 35.513002 | 3474.725256 | 3562.425944 |
0 | 2889198 | elevation | 3448.163403 | 3448.163403 | 5.088806 | 3443.074596 | 3453.252209 |
0 | 2889214 | elevation | 1558.948776 | 1558.909865 | 1.177185 | 1556.995965 | 1560.632596 |
0 | 2889222 | elevation | 3383.079127 | 3384.111898 | 20.186191 | 3357.855991 | 3407.269491 |
0 | 2889228 | elevation | 1562.467624 | 1562.329515 | 1.200751 | 1560.514595 | 1564.282919 |
0 | 2889258 | elevation | 1566.994821 | 1567.276414 | 1.405481 | 1564.551665 | 1569.605381 |
0 | 2889260 | elevation | 1570.061471 | 1569.926945 | 1.177150 | 1568.664712 | 1572.449691 |
0 | 2889264 | elevation | 1572.780278 | 1572.780278 | 0.221672 | 1572.558607 | 1573.001950 |
0 | 2889276 | elevation | 1574.920845 | 1574.883089 | 1.282822 | 1572.987986 | 1576.906272 |
Plot the mean elevation by comid#
# sort stats by topological stream order
stats = stats1.set_index("comid").loc[sort_ids[:-1]]
mr_fl["tmean"] = stats["mean"].values
pmin = mr_fl["tmean"].min()
pmax = mr_fl["tmean"].max()
pmin, pmax
import geoviews as gv
gv.extension("bokeh")
gv.tile_sources.EsriTerrain * gv.Path(mr_fl.to_crs(4326), vdims=["tmean"]).opts(width=600, height=300, aspect="equal",color="tmean", cmap="viridis", line_width=5, colorbar=True, clim=(pmin, pmax), clabel="Mean Elevation (m)", title="Mean Elevation by Stream Segment")
Plot the interpolated data as a scatter plot by comid#
import plotly.graph_objects as go
fig = go.Figure()
pts = pts1.groupby("comid")
for index in range(len(pts)):
group = pts.get_group(sort_ids[index])
fig.add_trace(go.Scatter(x=group["dist"], y=group["values"], mode='markers', marker=dict(size=5, color=group["values"], colorscale='Viridis', cmin=pmin, cmax=pmax), name=str(sort_ids[index])))
fig.update_layout(title="Stream-segment Interpolated Elevation 10m DEM", xaxis_title="Distance (m)", yaxis_title="Elevation (m)")
fig.show()
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
Cell In[13], line 1
----> 1 import plotly.graph_objects as go
2 fig = go.Figure()
3 pts = pts1.groupby("comid")
ModuleNotFoundError: No module named 'plotly'