Tip

For an interactive online version click here: Binder badge

Flow direction data#

The FlwdirRaster object is at the core of pyflwdir. It stores gridded flow-direction data in a common, actionable format, where each cell is represented by the linear index of its next downstream cell.

We currently support two local flow-direction (D8) formats: ArcGIS D8 and PCRaster LDD (see figure). We also support one global flow-direction format: CaMa-Flood NEXTXY. Local formats describe the downstream cell by its relative direction to a neighboring cell, while the global format describes it by row and column indices.

1937b332c6344c598fd79b43437a3f96

We read the flow direction raster data, including meta-data, using rasterio

[1]:
import rasterio

with rasterio.open("rhine_d8.tif", "r") as src:
    flwdir = src.read(1)
    transform = src.transform
    crs = src.crs
    latlon = crs.to_epsg() == 4326

Next, we parse this data to a FlwdirRaster object, the core object to work with flow direction data. In this step the D8 data is parsed to an actionable format.

NOTE: The first call to most methods may be slow because Numba compiles the code just in time. Subsequent calls to the same method, even with different arguments, are usually much faster!

[2]:
import pyflwdir

flw = pyflwdir.from_array(
    flwdir, ftype="d8", transform=transform, latlon=latlon, cache=True
)
[3]:
# When printing the FlwdirRaster instance we see its attributes.
print(flw)
{'ftype': 'd8',
 'idxs_ds': array([-1, -1, -1, ..., -1, -1, -1], shape=(679954,), dtype=int32),
 'idxs_pit': array([20994], dtype=int32),
 'idxs_seq': None,
 'latlon': True,
 'nnodes': 349847,
 'shape': (682, 997),
 'transform': Affine(0.008333333333325754, 0.0, 3.5666666664997138,
       0.0, -0.008333333333339965, 52.00833333330708)}

We can then use the many methods available on the FlwdirRaster object. See the FlwdirRaster API.

To visualize the flow directions, we derive a vector stream network using the streams() method. Each line represents a stream segment with a Strahler order of at least min_sto, as computed by stream_order(). The line features are converted to a GeoDataFrame for visualization.

[4]:
import geopandas as gpd

feats = flw.streams(min_sto=4)
gdf = gpd.GeoDataFrame.from_features(feats, crs=crs)
gdf.head()
[4]:
geometry idx idx_ds pit strord
0 LINESTRING (8.7125 46.65417, 8.72083 46.6625, ... 640691 635723 False 4
1 LINESTRING (8.8375 46.62917, 8.84583 46.6375, ... 643697 635723 False 4
2 LINESTRING (8.17917 46.57083, 8.1875 46.57083,... 650597 634651 False 4
3 LINESTRING (8.85417 46.69583, 8.8625 46.69583,... 635723 632737 False 5
4 LINESTRING (8.87917 46.7625, 8.8875 46.7625, 8... 627750 632737 False 4
[5]:
import numpy as np
from matplotlib import cm, colors

# local convenience methods (see utils.py script in notebooks folder)
from utils import quickplot  # data specific quick plot method

# keyword arguments passed to GeoDataFrame.plot()
gdf_plot_kwds = {
    "column": "strord",
    "cmap": colors.ListedColormap(cm.Blues(np.linspace(0.4, 1, 7))),
}
# plot streams with hillshade from elevation data (see utils.py)
ax = quickplot(gdfs=[(gdf, gdf_plot_kwds)], title="Streams")
../_images/_examples_flwdir_12_0.png