A8 - Retrieve and plot data from the US National Water Model

Course : CE 514 - Geospatial Software Development
Assignment 8 - Retrieve and plot data from the US National Water Model
Created by: Sujan Chandra Mondol
On February 11, 2025

The National Water Model (NWM) is a hydrologic modelling framework by National Oceanic and Atmospheric Administration that provides simulation of both the observed and forecasted streamflow and other hydrologic variables for about 2.7 million stream reaches over the entire continental United States (CONUS), southern Alaska, Hawaii, Puerto Rico, and the US Virgin Islands. It is designed around the Weather Research and Forecasting Hydrologic model (WRF-Hydro) and take leverage of datasets like Multi-Radar/Muti-Sensor System (MRMS) and Stage IV Multisensor Precipitation Estimator (MPE) radar-gauge observed precipitation data, and High Resolution Rapid Refresh (HRRR), Rapid Refresh (RAP), North American Mesoscale Nest (NAM-Nest), Global Forecasting System (GFS) and Climate Forecast System (CFS) Numerical Weather Prediction (NWP) forecast data.

The model is run on NOAA's Weather and Climate Operational Supercomputing System (WCOSS) for its several configurations:

  1. CONUS Analysis and Assimilation simulation
  2. CONUS Short-Range 18 h deterministic forecast
  3. CONUS Medium-Range 10 day ensemble forecast
  4. CONUS Long-Range 30 day ensemble forecast
  5. Hawaii and Puerto Rico/USVI Analysis and Assimilation current snapshot
  6. Hawaii and Puerto Rico/USVI 48 h short range forecast

Configuration Name Simulation Length Cycling Frequency Additional Information
CONUS Extended Analysis and Assimilation 28 hours lookback 1 time in a day features data assimilation
CONUS Standard Analysis and Assimilation 3 hours lookback 24 times in a day features data assimilation
CONUS Short Range Forecast 18 hours forecast 24 times in a day -
CONUS Medium Range Forecast 240 hours forecast 4 times in a day 7 ensemble members
CONUS Long Range Forecast 30 days forecast 4 times in a day 4 ensemble members
Hawaii Analysis and Assimilation 3 hours lookback 24 times in a day features data assimilation
Hawaii Short Range Forecast 48 hours forecast 2 times in a day -
PR/USVI Analysis and Assimilation 3 hours lookback 24 times in a day features data assimilation
PR/USVI Short Range Forecast 48 hours forecast 2 times in a day -


An Application Programming Interface (API) is a set of rules that enables applications to connect with each other for sharing data or features. Thus, it has become a useful conecpt in the context of water data accession and been implemented in several ways for the NWM also.

One of the recent developments of NWM API is deployed by CIROH that starts with creating a public dataset in Google Bigquery for the NWM streamflow data products. Based on various Google cloud products such as Cloud Run, Bigquery, and API Gateway, this approach deployed a representational state transfer (REST) architecture API for the streamflow forecast. The API enable the users to obatain the output dataset in tabular or structured format instead of the original format of timestamp snapshot of the whole spatial domain in the netCDF file. The API comes with three endpoints dedicated for three different data configuration:

  1. geometry
  2. analysis-assim
  3. forecast
Moreoever, the API parameters are specific to the particular endpoint and this provides minute control to the user over the range and type of data. The documentation page that comes with the API provides the user all necessary information to use the API without any difficulties.

Try Accessing NWM Forecast Data through API


How it works?

Piece of Code Explanation
function NWMResultsExtractor() {
Create a function in JavaScript that access the NWM API and extract results

  const reachID = parseInt(document.getElementById("reachID").value);
Obtain the reach ID as a constant from the input field in HTML

  const accessURL = `https://api.water.noaa.gov/nwps/v1/reaches/${reachID}/streamflow?series=short_range`;
Populate the API access URL using the reach ID and store it as a constant

    fetch(accessURL).then(response => {
Use the fetch function to access the API and indicate to store the response in a variable 'response'

      if (!response.ok) {
        throw new Error(`An HTTP error has been encountered. Error status: ${response.status}`);
      };
If the response is returned with any error, throw that error messgae

      return response.json();
    })
    .then(json_data => {
Process the response as JSON and store in the variable 'json_data'

      const streamflowData = json_data.shortRange.series.data;
      const timestamps = streamflowData.map(item => item.validTime);
      const flowValues = streamflowData.map(item => item.flow);
Extract the streamflow data as streamflowData and create timestamps and flowValues data series from that
      const tableElementCatcher = document.getElementById('timeseries-datatable');
Grab the HTML element inside which dataresults to be shown
      tableElementCatcher.style.display = 'block';
Show the results element that is otherwise not displayed by default
      const table = tableElementCatcher.getElementsByTagName('tbody')[0];
Grab the table element to enable writing table contents from within JS
      const maxLength = Math.max(timestamps.length, flowValues.length);
Identify the maximum value between the lengths of timestamp and flowValues series to use in a for loop later
      for (let i = 0; i < maxLength; i++) {
Run a for loop to go over each timeseries data point
    
        const row = table.insertRow();
        const timestampCell = row.insertCell();
        const flowCell = row.insertCell();
            
For each of the flowValues, create a row in the timeseries-datatable and create two cells, one for timestamp and another for flow value
    
        if (i==0) {
          const chart = row.insertCell();
          chart.innerHTML = '<canvas id="streamflowChart"></canvas>';
          chart.rowSpan = '18';
          chart.columnWidth = '900px';
        }
            
In the very first iteration, create a placeholder for the timeseries graph in a table cell and spans it along all rows in the table
    
        timestampCell.textContent = timestamps[i] || ""; 
        flowCell.textContent = flowValues[i] || ""; 
      };
            
Populate the created cells for timestamp and flow with actual values from the corresponding data series and end the for loop
    
      const chartElementCatcher = document.getElementById('streamflowChart');
      const ctx = chartElementCatcher.getContext('2d');
            
Grab the element in which the timeseries graph is to be shown and create a chart for that element with the Chart.js library
    
      new Chart(ctx, {
        type: 'line',
        data: {
            labels: timestamps,
            datasets: [{
                label: 'Streamflow Forecast (Short Range)',
                data: flowValues,
                borderColor: 'teal',
                borderWidth: 1,
                fill: false}]
            },
        options: {
            responsive: true,
            scales: {
                x: {
                    display: true,
                    title: {
                        display: true,
                        text: 'Time'}
                    },
                y: {
                    display: true,
                    title: {
                        display: true,
                        text: 'Streamflow (cfs)'}    
                    } 
                }
            }
        });
    }
            
Assign the chart elements and attributes as per the convention of Chart.js open source library
    
      ).catch(error => {
        console.error('Error fetching or processing data:', error);
        const chartCanvas = document.getElementById('streamflowChart');
        chartCanvas.innerHTML = "<p>Error loading chart</p>";
      });
            
If any error is encountered following the fetch function up to this line of code, show the corresponding error message
}
Close the function body