diff --git a/csv_functions.py b/csv_functions.py index c9396a0b..b6d255a5 100644 --- a/csv_functions.py +++ b/csv_functions.py @@ -1562,6 +1562,33 @@ def arctic_hydrology_csv(data, filename_prefix, source_metadata): metadata += f"# The following hydrologic statistics are calculated from modeled daily streamflow data. {source_notes[source_metadata]}\n" else: metadata += "# The following hydrologic statistics are calculated from modeled daily streamflow data:\n" + metadata += "# dh1: Mean annual maximum 1-day average flow (cubic feet per second - temporal).\n" + metadata += "# dh2: Mean annual maximum 3-day average flow (cubic feet per second - temporal).\n" + metadata += "# dh3: Mean annual maximum 7-day average flow (cubic feet per second - temporal).\n" + metadata += "# dh4: Mean annual maximum 30-day average flow (cubic feet per second - temporal).\n" + metadata += "# dh5: Mean annual maximum 90-day average flow (cubic feet per second - temporal).\n" + metadata += "# dh15: Median annual average duration of high flow pulses above the 75th percentile (days/year - temporal).\n" + metadata += "# dl1: Mean annual minimum 1-day average flow (cubic feet per second - temporal).\n" + metadata += "# dl2: Mean annual minimum 3-day average flow (cubic feet per second - temporal).\n" + metadata += "# dl3: Mean annual minimum 7-day average flow (cubic feet per second - temporal).\n" + metadata += "# dl4: Mean annual minimum 30-day average flow (cubic feet per second - temporal).\n" + metadata += "# dl5: Mean annual minimum 90-day average flow (cubic feet per second - temporal).\n" + metadata += "# dl16: Median annual average duration of low flow pulses below the 25th percentile (days/year - temporal).\n" + metadata += "# lf1: Median annual number of days below a threshold of 0.1 cubic feet per second per square mile (days/year - temporal).\n" + metadata += "# spr_dur3: Median spring (April-June) maximum of 3-day moving average flows (cubic feet per second - temporal).\n" + metadata += "# spr_dur7: Median spring (April-June) maximum of 7-day moving average flows (cubic feet per second - temporal).\n" + metadata += "# sum_dur3: Median summer (July-September) minimum of 3-day moving average flow (cubic feet per second - temporal).\n" + metadata += "# sum_dur7: Median summer (July-September) minimum of 7-day moving average flow (cubic feet per second - temporal).\n" + metadata += "# fh1: Mean annual count of high flow pulses above the 75th percentile (number of events/year - temporal).\n" + metadata += "# fh5: Mean annual flood frequency above median flow (number of events/year - temporal).\n" + metadata += "# fh6: Mean annual flood frequency above 3 times median flow (number of events/year - temporal).\n" + metadata += "# fh7: Mean annual flood frequency above 7 times median flow (number of events/year - temporal).\n" + metadata += "# fl1: Mean annual count of low flow pulses below the 25th percentile (number of events/year - temporal).\n" + metadata += "# fl3: Mean annual count of events below 5 percent of mean flow (number of events/year - temporal).\n" + metadata += "# spr_freq: Median spring (April-June) count of flow events above the 10th percentile of the full record (number of events/year - temporal).\n" + metadata += "# sum_freq: Median summer (July-September) count of flow events below the 90th percentile of the full record (number of events/year - temporal).\n" + metadata += "# ma3: Coefficient of variation (standard deviation/mean) of annual daily flows; mean of annual CVs (percent - temporal).\n" + metadata += "# ma4: Standard deviation of percentiles of log-transformed flow divided by mean of those percentiles (percent - spatial).\n" metadata += "# ma12: Mean of monthly flow values for January (cubic feet per second - temporal).\n" metadata += "# ma13: Mean of monthly flow values for February (cubic feet per second - temporal).\n" metadata += "# ma14: Mean of monthly flow values for March (cubic feet per second - temporal).\n" @@ -1575,6 +1602,19 @@ def arctic_hydrology_csv(data, filename_prefix, source_metadata): metadata += "# ma22: Mean of monthly flow values for November (cubic feet per second - temporal).\n" metadata += "# ma23: Mean of monthly flow values for December (cubic feet per second - temporal).\n" metadata += "# ma99: Mean of monthly flow values for the entire year. Compute the mean of the monthly mean flows for each month of the year. MA99 is the mean of these 12 values (cubic feet per second - temporal).\n" + metadata += "# mh14: Median of annual (maximum flow / median annual flow) ratios (dimensionless - temporal).\n" + metadata += "# mh20: Mean annual maximum flow divided by drainage area (cubic feet per second/square mile - temporal).\n" + metadata += "# ml17: Base flow index: mean of annual (7-day minimum flow / mean annual flow) ratios (dimensionless - temporal).\n" + metadata += "# spr_mag: Median spring (April-June) maximum flow divided by drainage area (cubic feet per second/square mile - temporal).\n" + metadata += "# sum_cv: Median annual coefficient of variation of summer (July-September) daily flows (percent - temporal).\n" + metadata += "# sum_mag: Median summer (July-September) minimum flow divided by drainage area (cubic feet per second/square mile - temporal).\n" + metadata += "# ra1: Mean rise rate: mean of positive daily flow changes (cubic feet per second/day - temporal).\n" + metadata += "# ra3: Mean fall rate: mean of negative daily flow changes (cubic feet per second/day - temporal).\n" + metadata += "# ra8: Median annual number of flow direction reversals (days - temporal).\n" + metadata += "# spr_ord: Median Julian date of spring (April-June) maximum flow (Julian day - temporal).\n" + metadata += "# sum_ord: Median Julian date of summer (July-September) minimum flow (Julian day - temporal).\n" + metadata += "# th1: Median Julian date of annual maximum flow (Julian day - temporal).\n" + metadata += "# tl1: Median Julian date of annual minimum flow (Julian day - temporal).\n" else: if isinstance(source_metadata, str) and source_metadata in source_notes: metadata += f"# Climatologies are calculated from modeled daily streamflow data. {source_notes[source_metadata]}\n" diff --git a/generate_urls.py b/generate_urls.py index b2810824..c99230be 100644 --- a/generate_urls.py +++ b/generate_urls.py @@ -133,21 +133,33 @@ def generate_wfs_conus_hydrology_url(stream_id): def generate_wfs_arctic_hydrology_url(stream_id): """ Generate a WFS URL for fetching arctic hydrology data for a given stream ID. Returns both attributes and geometry for a single stream ID. - If the stream ID is an empty string, returns only attributes for all streams.""" + If the stream ID is an empty string, returns only COMID attribute for all streams. + """ if stream_id == "": wfs_url = ( GS_BASE_URL - + "wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=hydrology:arctic_segments&propertyName=(COMID)&outputFormat=application/json" + + "wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=hydrology:arctic_rivers_segments_joined_3338_simplified&propertyName=(COMID)&outputFormat=application/json" ) return wfs_url else: wfs_url = ( GS_BASE_URL - + f"wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=hydrology:arctic_segments&propertyName=(COMID,the_geom)&outputFormat=application/json&cql_filter=(COMID={stream_id})" + + f"wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=hydrology:arctic_rivers_segments_joined_3338_simplified&propertyName=(COMID,the_geom,Gauge_ID,ID_1,ID_2,Name,outlet)&outputFormat=application/json&cql_filter=(COMID={stream_id})" ) return wfs_url +def generate_wfs_arctic_hydrology_stats_url(stream_id): + """ + Generate a WFS URL for fetching arctic hydrology summary stats for a given stream ID + from the arctic_rivers_segments_stats_simplified layer. + """ + return ( + GS_BASE_URL + + f"wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=hydrology:arctic_rivers_segments_stats_simplified&outputFormat=application/json&cql_filter=(COMID={stream_id})" + ) + + def generate_usgs_gauge_daily_streamflow_data_url(gauge_id, start_date, end_date): """ Generate a USGS OGC API URL for fetching daily streamflow data for a given gauge ID and date range. diff --git a/routes/arctic_hydrology.py b/routes/arctic_hydrology.py index b58f09ce..752f8650 100644 --- a/routes/arctic_hydrology.py +++ b/routes/arctic_hydrology.py @@ -17,7 +17,10 @@ ) from generate_requests import generate_conus_hydrology_wcs_str -from generate_urls import generate_wfs_arctic_hydrology_url +from generate_urls import ( + generate_wfs_arctic_hydrology_url, + generate_wfs_arctic_hydrology_stats_url, +) from fetch_data import fetch_data, fetch_layer_data, describe_via_wcps from validate_request import get_axis_encodings from postprocessing import prune_nulls_with_max_intensity @@ -26,7 +29,7 @@ from . import routes coverages = { - "stats": ["ak_hydro_segments_stats_combined"], + "stats": ["ak_hydro_segments_mhit_stats_combined"], "doy_climatology": ["ak_hydro_segments_doy_climatology"], } @@ -36,94 +39,6 @@ "gcm_diff_applied_to_cheng": 2, } -# TODO: populate this with actual values from the GS layer after computing via MHIT -_SUMMARY_STUB = { - "ma99_hist": { - "value": None, - "range_low": None, - "range_high": None, - "units": "cfs", - "description": "historical mean annual flow", - }, - "ma99_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "percent", - "description": "projected change in mean annual flow", - }, - "dh1_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "percent", - "description": "projected change in maximum 1-day flow", - }, - "dl1_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "percent", - "description": "projected change in minimum 1-day flow", - }, - "dh15_hist": { - "value": None, - "range_low": None, - "range_high": None, - "units": "days", - "description": "historical high flow pulse duration", - }, - "dh15_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "days", - "description": "projected change in high flow pulse duration", - }, - "dl16_hist": { - "value": None, - "range_low": None, - "range_high": None, - "units": "days", - "description": "historical low flow pulse duration", - }, - "dl16_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "days", - "description": "projected change in low flow pulse duration", - }, - "fh1_hist": { - "value": None, - "range_low": None, - "range_high": None, - "units": "events", - "description": "historical high flood pulse count", - }, - "fh1_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "events", - "description": "projected change in high flood pulse count", - }, - "fl1_hist": { - "value": None, - "range_low": None, - "range_high": None, - "units": "events", - "description": "historical low flood pulse count", - }, - "fl1_delta": { - "value": None, - "range_low": None, - "range_high": None, - "units": "events", - "description": "projected change in low flood pulse count", - }, -} - async def get_decode_dicts_from_axis_attributes(cov_ids): """ @@ -185,7 +100,7 @@ async def get_features(stream_id): async with ClientSession() as session: layer_data = await fetch_layer_data(url, session) - gdf = gpd.GeoDataFrame.from_features(layer_data["features"], crs="EPSG:4326") + gdf = gpd.GeoDataFrame.from_features(layer_data["features"], crs="EPSG:3338") gdf["geometry"] = gdf["geometry"].make_valid() return gdf @@ -193,6 +108,248 @@ async def get_features(stream_id): return render_template("400/bad_request.html"), 400 +async def get_stats_features(stream_id): + """Function to fetch summary stat attributes from the WFS stats layer for a given stream ID. + Args: + stream_id (str): Stream ID for the hydrology data + Returns: + GeoDataFrame with stat attributes, or None if unavailable.""" + try: + url = generate_wfs_arctic_hydrology_stats_url(stream_id) + async with ClientSession() as session: + layer_data = await fetch_layer_data(url, session) + features = layer_data.get("features", []) + if not features: + return None + gdf = gpd.GeoDataFrame([f["properties"] for f in features]) + return gdf.replace({None: np.nan}) + except Exception: + return None + + +def populate_feature_stat_attributes_summary(data_dict, gdf): + """Function to populate the summary stats from the WFS stats layer into the data dictionary. + Args: + data_dict (dict): Data dictionary to populate with summary stats + gdf (GeoDataFrame or None): GeoDataFrame with stat attributes from the stats layer + Returns: + Data dictionary with summary stats populated, or null-valued summary if gdf is unavailable. + """ + summary_values = {} + + ### MEAN FLOWS: + ma99_hist_value = ( + int(round(gdf.loc[0].ma99_hist, 0)) + if not np.isnan(gdf.loc[0].ma99_hist) + else None + ) + if ma99_hist_value is not None and ma99_hist_value > 5: + ma99_hist_value = int(round(gdf.loc[0].ma99_hist / 5) * 5) + summary_values["ma99_hist"] = { + "value": ma99_hist_value, + "range_low": None, + "range_high": None, + "units": "cfs", + "description": "historical mean annual flow", + } + + summary_values["ma99_delta"] = { + "value": ( + int(round(gdf.loc[0].ma99_avg_d, 0)) + if not np.isnan(gdf.loc[0].ma99_avg_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].ma99_min_d, 0)) + if not np.isnan(gdf.loc[0].ma99_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].ma99_max_d, 0)) + if not np.isnan(gdf.loc[0].ma99_max_d) + else None + ), + "units": "percent", + "description": "projected change in mean annual flow", + } + + ### MIN AND MAX FLOWS: + # value is max of model maximums (range_high); range_low is minimum of model maximums + summary_values["dh1_delta"] = { + "value": ( + int(round(gdf.loc[0].dh1_max_d, 0)) + if not np.isnan(gdf.loc[0].dh1_max_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].dh1_min_d, 0)) + if not np.isnan(gdf.loc[0].dh1_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].dh1_max_d, 0)) + if not np.isnan(gdf.loc[0].dh1_max_d) + else None + ), + "units": "percent", + "description": "projected change in maximum 1-day flow", + } + + # value is min of model minimums (range_low); range_high is maximum of model minimums + summary_values["dl1_delta"] = { + "value": ( + int(round(gdf.loc[0].dl1_min_d, 0)) + if not np.isnan(gdf.loc[0].dl1_min_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].dl1_min_d, 0)) + if not np.isnan(gdf.loc[0].dl1_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].dl1_max_d, 0)) + if not np.isnan(gdf.loc[0].dl1_max_d) + else None + ), + "units": "percent", + "description": "projected change in minimum 1-day flow", + } + + ### FLOOD DURATION: + summary_values["dh15_hist"] = { + "value": ( + int(round(gdf.loc[0].dh15_hist, 0)) + if not np.isnan(gdf.loc[0].dh15_hist) + else None + ), + "range_low": None, + "range_high": None, + "units": "days", + "description": "historical high flow pulse duration", + } + + summary_values["dh15_delta"] = { + "value": ( + int(round(gdf.loc[0].dh15_avg_d, 0)) + if not np.isnan(gdf.loc[0].dh15_avg_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].dh15_min_d, 0)) + if not np.isnan(gdf.loc[0].dh15_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].dh15_max_d, 0)) + if not np.isnan(gdf.loc[0].dh15_max_d) + else None + ), + "units": "days", + "description": "projected change in high flow pulse duration", + } + + summary_values["dl16_hist"] = { + "value": ( + int(round(gdf.loc[0].dl16_hist, 0)) + if not np.isnan(gdf.loc[0].dl16_hist) + else None + ), + "range_low": None, + "range_high": None, + "units": "days", + "description": "historical low flow pulse duration", + } + + summary_values["dl16_delta"] = { + "value": ( + int(round(gdf.loc[0].dl16_avg_d, 0)) + if not np.isnan(gdf.loc[0].dl16_avg_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].dl16_min_d, 0)) + if not np.isnan(gdf.loc[0].dl16_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].dl16_max_d, 0)) + if not np.isnan(gdf.loc[0].dl16_max_d) + else None + ), + "units": "days", + "description": "projected change in low flow pulse duration", + } + + ### FLOOD PULSE COUNT: + summary_values["fh1_hist"] = { + "value": ( + int(round(gdf.loc[0].fh1_hist, 0)) + if not np.isnan(gdf.loc[0].fh1_hist) + else None + ), + "range_low": None, + "range_high": None, + "units": "events", + "description": "historical high flood pulse count", + } + + summary_values["fh1_delta"] = { + "value": ( + int(round(gdf.loc[0].fh1_avg_d, 0)) + if not np.isnan(gdf.loc[0].fh1_avg_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].fh1_min_d, 0)) + if not np.isnan(gdf.loc[0].fh1_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].fh1_max_d, 0)) + if not np.isnan(gdf.loc[0].fh1_max_d) + else None + ), + "units": "events", + "description": "projected change in high flood pulse count", + } + + summary_values["fl1_hist"] = { + "value": ( + int(round(gdf.loc[0].fl1_hist, 0)) + if not np.isnan(gdf.loc[0].fl1_hist) + else None + ), + "range_low": None, + "range_high": None, + "units": "events", + "description": "historical low flood pulse count", + } + + summary_values["fl1_delta"] = { + "value": ( + int(round(gdf.loc[0].fl1_avg_d, 0)) + if not np.isnan(gdf.loc[0].fl1_avg_d) + else None + ), + "range_low": ( + int(round(gdf.loc[0].fl1_min_d, 0)) + if not np.isnan(gdf.loc[0].fl1_min_d) + else None + ), + "range_high": ( + int(round(gdf.loc[0].fl1_max_d, 0)) + if not np.isnan(gdf.loc[0].fl1_max_d) + else None + ), + "units": "events", + "description": "projected change in low flood pulse count", + } + + data_dict["summary"] = summary_values + return data_dict + + def package_stats_data(stream_id, ds): """ Function to package the stats data into a dictionary for JSON serialization. @@ -462,11 +619,24 @@ def populate_feature_attributes(data_dict, gdf): Returns: Data dictionary with the vector attributes populated.""" - data_dict["name"] = "" - data_dict["huc8"] = None - data_dict["huc8_outlet"] = None - data_dict["latitude"] = round(gdf.loc[0].geometry.representative_point().y, 4) - data_dict["longitude"] = round(gdf.loc[0].geometry.representative_point().x, 4) + # data_dict["name"] = "" # arctic rivers segments do not have stream names associated + + # gauge ID is blank for most features; normalize None/NaN to "" so the key is always present + gauge_id_raw = gdf.loc[0].get("Gauge_ID", None) + data_dict["gauge_id"] = gauge_id_raw if isinstance(gauge_id_raw, str) else "" + + # the watershed ID matches the GVV code for HUC8 in Alaska or Yukon watershed in Canada + # all Yukon watersheds begin with "YTHYDRO" while HUC8s are just numeric + data_dict["watershed"] = gdf.loc[0].get("ID_1", None) + outlet = gdf.loc[0].get("outlet", None) + data_dict["watershed_outlet"] = ( + bool(outlet) if outlet is not None and not np.isnan(outlet) else None + ) + + # copy and convert gdf to WGS84 for lat/lon extraction + gdf_4326 = gdf.to_crs("EPSG:4326") + data_dict["latitude"] = round(gdf_4326.loc[0].geometry.representative_point().y, 4) + data_dict["longitude"] = round(gdf_4326.loc[0].geometry.representative_point().x, 4) return data_dict @@ -498,6 +668,8 @@ def run_get_arctic_hydrology_stats_data(stream_id): if isinstance(gdf, tuple): return gdf # return 400 if gdf is a tuple + stats_gdf = asyncio.run(get_stats_features(stream_id)) + try: # fetch data and metadata decode_dict = asyncio.run( @@ -540,12 +712,12 @@ def run_get_arctic_hydrology_stats_data(stream_id): except Exception: return render_template("500/server_error.html"), 500 - # add stub summary dict for frontend interoperability with conus_hydrology - data_dict["summary"] = copy.deepcopy(_SUMMARY_STUB) + data_dict = populate_feature_stat_attributes_summary(data_dict, stats_gdf) return jsonify(data_dict) except Exception as exc: + if hasattr(exc, "status") and exc.status == 404: return render_template("404/no_data.html"), 404 return render_template("500/server_error.html"), 500 @@ -672,7 +844,9 @@ def run_get_arctic_hydrology_hydroviz(stream_id): )[0] pgw_ds = asyncio.run( fetch_hydro_data( - coverages["stats"], stream_id, source=stat_source_encodings["original_gcm"] + coverages["stats"], + stream_id, + source=stat_source_encodings["original_gcm"], ) )[0] for dim, mapping in stats_decode_dict.items(): @@ -848,16 +1022,16 @@ def run_get_arctic_hydrology_hydroviz(stream_id): } response = { - "gauge_id": None, - "huc8": None, - "huc8_outlet": None, + "gauge_id": stats.get("gauge_id"), + "huc8": stats.get("watershed"), + "huc8_outlet": stats.get("watershed_outlet"), "hydrograph": hydrograph, "id": stats["id"], - "name": stats["name"], + "name": stats.get("name"), "monthly_flow": monthly_flow, "max_flow_dates": max_flow_dates, "stats": table_stats, - "summary": copy.deepcopy(_SUMMARY_STUB), + "summary": stats.get("summary"), } return jsonify(response) diff --git a/templates/documentation/arctic_hydrology.html b/templates/documentation/arctic_hydrology.html index e4bc238c..22087be6 100644 --- a/templates/documentation/arctic_hydrology.html +++ b/templates/documentation/arctic_hydrology.html @@ -7,8 +7,11 @@
- Query hydrologic statistics for all models and scenarios. Statistics are - computed over historical (1990–2021) and projected mid-century - (2034–2065) eras. These statistics are defined + Query hydrologic statistics for all models. Statistics are computed over + historical (1990–2021) and projected mid-century (2034–2065) eras. + These statistics are defined below.
@@ -51,7 +54,28 @@?format=csv to
- the URL. ?source=
+ parameter. Accepted values are:
+ gcm_diff_applied_to_cheng (default) —
+ GCM-projected changes applied to the historical Cheng baseline. PGW
+ models are not included.
+ original_gcm — raw output from the original GCM
+ runs. Includes PGW models.
+ gcm_diff — ratio or absolute difference between
+ the projected and historical GCM runs. These are not actual
+ statistic values; apply them to your own historical baseline to
+ approximate future values.
+ ?source=original_gcm&format=csv).
- Query daily streamflow climatologies for all models and scenarios. Useful for - constructing hydrographs. Minimum, maximum, and mean values for each day of - year are computed over historical (1990–2021) and projected mid-century + Query daily streamflow climatologies for all models. Useful for constructing + hydrographs. Minimum, maximum, and mean values for each day of year are + computed over historical (1990–2021) and projected mid-century (2034–2065) eras.
@@ -87,7 +111,22 @@?format=csv to
- the URL. ?source=
+ parameter. Accepted values are:
+ gcm_diff_applied_to_cheng (default) —
+ GCM-projected changes applied to the historical Cheng baseline. PGW
+ models are not included.
+ original_gcm — raw output from the original GCM
+ runs. Includes PGW models.
+ ?source=original_gcm&format=csv).
Note that latitude and longitude values represent the approximate centroid of - the stream segment. Also note that not all stream segments are named. The - above output is structured like this: + the stream segment. The above output is structured like this:
@@ -158,7 +222,7 @@@@ -189,35 +264,35 @@Modeled hydrologic statistics
<era>: { <variable>: <value>, ... - }, + }, ... }, ... @@ -178,7 +242,18 @@Modeled hydrologic statistics
... } }, - "name": <name of stream segment> + "summary": { + <statistic>: { + "description": <description of statistic>, + "range_high": <maximum projected change across models>, + "range_low": <minimum projected change across models>, + "units": <units of statistic>, + "value": <central projected value> + }, + ... + }, + "watershed": <HUC8 or Yukon watershed ID>, + "watershed_outlet": <true if segment is a watershed outlet> }
Note that latitude and longitude values represent the approximate centroid of - the stream segment. Also note that not all stream segments are named. Modeled - data uses a 366 day year. The above output is structured like this: + the stream segment. Modeled data uses a 366 day year. The above output is + structured like this:
@@ -276,23 +352,25 @@@@ -307,6 +385,175 @@Modeled daily streamflow climatologies
], ... }, - "id": <stream ID>, - "latitude": <latitude of stream segment>, - "latitude": <latitude of stream segment>, - "longitude": <longitude of stream segment>, - "metadata": { - "source": { - "citation": <academic reference for source data> - }, - "variables": { - <variable>: { - "description": <description of variable>, - "units": <units of variable> - }, - } + ... + }, + "id": <stream ID>, + "latitude": <latitude of stream segment>, + "longitude": <longitude of stream segment>, + "metadata": { + "source": { + "citation": <academic reference for source data> }, - "name": <name of stream segment> - } + "variables": { + <variable>: { + "description": <description of variable>, + "units": <units of variable> + }, + ... + } + }, + "watershed": <HUC8 or Yukon watershed ID>, + "watershed_outlet": <true if segment is a watershed outlet> }
dh1dh2dh3dh4dh5dh15dl1dl2dl3dl4dl5dl16lf1spr_dur3spr_dur7sum_dur3sum_dur7fh1fh5fh6fh7fl1fl3spr_freqsum_freqma3ma4ma12ma99mh14mh20ml17spr_magsum_cvsum_magra1ra3ra8spr_ordsum_ordth1tl1