01 - Getting watershed boundaries

Region Selection and Map Preview with Ipyleaflet

In this notebook, you will extract a selected watershed from the HydroSHEDS database (see the reference manual for more information on HydroSHEDS). A GeoJSON with the watershed boundaries will be available for download and usable for other tasks such as extracting meteorological data covered in the next notebooks.

# Import the necessary libraries to format, send, and parse our returned results
import os

import birdy
import geopandas as gpd
import ipyleaflet
import ipywidgets

If you are running this locally (and not on the PAVICS-Hydro server), and your notebook is version prior to 5.3, you might need to run this command jupyter nbextension enable --py --sys-prefix ipyleaflet. For more information see https://ipyleaflet.readthedocs.io/en/latest/installation.html.

This next box is all boilerplate, you do not need to understand it or play with it. Simply run it! Many such code snippets are provided throughout the notebooks to make your life easier. You can then modify some options to taylor the code to your needs.

# Create WPS instances# Set environment variable WPS_URL to "http://localhost:9099" to run on the default local server
pavics_url = "https://pavics.ouranos.ca"
raven_url = os.environ.get("WPS_URL", f"{pavics_url}/twitcher/ows/proxy/raven/wps")

raven = birdy.WPSClient(raven_url)

# Build an interactive map with ipyleaflet
initial_lat_lon = (48.63, -74.71)

leaflet_map = ipyleaflet.Map(
    center=initial_lat_lon,
    basemap=ipyleaflet.basemaps.OpenTopoMap,
)

# Add a custom zoom slider
zoom_slider = ipywidgets.IntSlider(description="Zoom level:", min=1, max=10, value=6)
ipywidgets.jslink((zoom_slider, "value"), (leaflet_map, "zoom"))
widget_control1 = ipyleaflet.WidgetControl(widget=zoom_slider, position="topright")
leaflet_map.add_control(widget_control1)

# Add a marker to the map
marker = ipyleaflet.Marker(location=initial_lat_lon, draggable=True)
leaflet_map.add_layer(marker)

# Add an overlay widget
html = ipywidgets.HTML("""Hover over a feature!""")
html.layout.margin = "0px 10px 10px 10px"

control = ipyleaflet.WidgetControl(widget=html, position="bottomleft")
leaflet_map.add_control(control)


def update_html(feature, **kwargs):
    html.value = """
        <h2><b>USGS HydroBASINS</b></h2>
        <h4>ID: {}</h4>
        <h4>Upstream Area: {} sq. km.</h4>
        <h4>Sub-basin Area: {} sq. km.</h4>
    """.format(
        feature["properties"]["id"],
        feature["properties"]["UP_AREA"],  #
        feature["properties"]["SUB_AREA"],
    )

Using the map to select the outlet of the watershed

When using the “leaflet_map” command, an interative map will be displayed.

Note that a blue marker will be displayed in the middle of the map, which can be dragged by interacting directly with it. Try dragging and placing the marker at the mouth of a river, over a large lake such as Lac Saint-Jean (next to Alma, east of the initial marker position), or anywhere else within North America. This coordinate will be used to find and extract the closest watershed outlet from the Hydrosheds database (see the reference manual for more info on Hydrosheds). The watershed ID and area will be displayed at the bottom left corner of the map.

The user can zoom in and out on the map either by:

  • Using the Zoom level on the top right corner;

  • Using the + / - icons on the top left corner;

  • Double-clicking on the map on the area to zoom in.

# Load the map in the notebook
leaflet_map
# Display the lat/lon coordinates of the marker location.
user_lonlat = list(reversed(marker.location))
print(user_lonlat)
# Get the shape of the watershed contributing to flow at the selected location.
resp = raven.hydrobasins_select(location=str(user_lonlat), aggregate_upstream=True)

Before continuing, wait for the process above to finish

This can be monitored when the “[*]:” on the left of the cell is replaced with a number.

# Extract the URL of the resulting GeoJSON feature
feat = resp.get(asobj=False).feature
print(
    "This is the geoJSON file that can be used as the watershed contour in other toolboxes:"
)
print("")
print(feat)
print("")

BEFORE CONTINUING:

  • If you are working in the writable-workspace, you will want to download the .geojson file at the link above and deposit it into your workspace on the left of your screen.

  • If you are running this in the default workspace after logging in, the workspace is read-only so we will provide files for you, and you can ignore this file for the time being.

# Print the properties from the extracted watershed
gdf = gpd.read_file(feat)
gdf

Now we will add the extracted watershed to the map above!

Scroll back up after executing the next cell to see the watershed displayed in blue on the map. You may reextract another watershed by moving restarting the kernel or running all the cells from the beginning to reload the map.

# Adding the GeoJSON to the map above.
user_geojson = ipyleaflet.GeoData(
    geo_dataframe=gdf,
    style={
        "color": "blue",
        "opacity": 1,
        "weight": 1.9,
        "fillOpacity": 0.5,
    },
    hover_style={"fillColor": "#b08a3e", "fillOpacity": 0.9},
)

leaflet_map.add_layer(user_geojson)
user_geojson.on_hover(update_html)

Congratulations!

You have successfully created a watershed boundary file that can be used in the following notebooks. If you already have the boundaries of your watershed of interest, then you can upload them to your workspace instead of using this notebook to generate them. a geojson file is accepted, as is a shapefile. For shapefiles, provide a zip containing all the shape data (.shp, .shx, .dbf, .prj, etc.).