Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Earthkit-hydro: Computing Lengths and Distances

earthkit-hydro-logo

Earthkit-hydro: Computing Lengths and Distances

Tnis notebook will show a simple example of computing distances and lengths along river networks.

import earthkit.hydro as ekh
import earthkit.plots as ekp
import numpy as np

network = ekh.river_network.load("efas", "5")

locations = {
    "Reading": (50.736364, 7.10807),
    "Bonn": (51.461325, -0.967884)
}
River network not found in cache (/etc/ecmwf/ssd/ssd1/jupyterhub/macw-jupyterhub/tmpdirs/macw.39412013/tmpy8hsl0vk_earthkit_hydro/1.2_0dc8123bbf944ff1cb86f41bc7506e891baaa990666d836fc0cf2edd503916db.joblib).
River network loaded, saving to cache (/etc/ecmwf/ssd/ssd1/jupyterhub/macw-jupyterhub/tmpdirs/macw.39412013/tmpy8hsl0vk_earthkit_hydro/1.2_0dc8123bbf944ff1cb86f41bc7506e891baaa990666d836fc0cf2edd503916db.joblib).

Distances and Lengths

Computing how far points on a river network are from each other is a common task, facilitated by the distance and length submodules.

Lengths

Lengths are the sum of all lengths per node/gridcell, including at the sources. By default, lengths are assumed to be unit lengths, giving the length in terms of number of gridcells. Either a maximum or minimum length can be found, in either the upstream or downstream direction, or both (undirected lengths).

Numerous start locations can be specified in which case the algorithm returns the minimum/maximum length starting from any of the start locations.

da = ekh.length.min(network, locations, upstream=True, downstream=False)

chart = ekp.Map(domain=[-6, 16, 45, 56])
chart.quickplot(da)
chart.legend(label="{variable_name}")
chart.title("Minimum Length Upstream")
chart.coastlines()
chart.gridlines()
chart.show()
<Figure size 700x800 with 2 Axes>
da = ekh.length.min(network, locations, upstream=True, downstream=True)

chart = ekp.Map(domain=[-6, 16, 45, 56])
chart.quickplot(da)
chart.legend(label="{variable_name}")
chart.title("Minimum Length Upstream and Downstream")
chart.coastlines()
chart.gridlines()
chart.show()
<Figure size 700x800 with 2 Axes>

Custom node/gridcell lengths can of course also be specified.

pixel_lengths = np.random.rand(*network.shape)

da = ekh.length.min(network, locations, field=pixel_lengths, upstream=True, downstream=True)

chart = ekp.Map()
chart.quickplot(da)
chart.legend(label="{variable_name}")
chart.title("Minimum Length Upstream and Downstream")
chart.coastlines()
chart.gridlines()
chart.show()
<Figure size 700x800 with 2 Axes>

Distances

Distances are similar to lengths, but are computed by summing the edge distances starting from the source nodes. Again, unit distances are assumed for each edge.

In practice, this means that with default behaviour the distance at each point will be one fewer than the length because there is one fewer edge per path compared to the number of nodes.

np.all(ekh.distance.array.min(network, locations, return_type="masked") == ekh.length.array.min(network, locations, return_type="masked") - 1)
np.True_

Convenience functions

It is common to find lengths/distances to sources/sinks, so these methods are provided for convenience. Both longest and shortest paths are supported.

da = ekh.distance.to_source(network, path="longest")

chart = ekp.Map()
chart.quickplot(da)
chart.legend(label="{variable_name}")
chart.title("Longest Path Distance to Source")
chart.coastlines()
chart.gridlines()
chart.show()
<Figure size 700x800 with 2 Axes>
da = ekh.length.to_sink(network, path="longest")

chart = ekp.Map()
chart.quickplot(da)
chart.legend(label="{variable_name}")
chart.title("Longest Path Length to Sink")
chart.coastlines()
chart.gridlines()
chart.show()
<Figure size 700x800 with 2 Axes>