For each point in a table, traverse the stream network upstream or
downstream and aggregate features (streams, lakes, etc.) found on
that network. Wraps fwa_upstream() / fwa_downstream() with
GROUP BY aggregation.
Usage
frs_aggregate(
conn,
points,
features,
metrics,
id_col = c("blue_line_key", "downstream_route_measure"),
direction = "upstream",
where = NULL,
to = NULL,
overwrite = TRUE
)Arguments
- conn
A DBI::DBIConnection object (from
frs_db_conn()).- points
Character. Table of locations to aggregate from. Must have
blue_line_keyanddownstream_route_measurecolumns (or the equivalents set viaoptions()), plus a unique ID column.- features
Character. Table of features to aggregate (e.g. classified streams, lakes). Must have wscode/localcode columns.
- metrics
Named character vector. Names are output column names, values are SQL expressions. Example:
c(length_m = "SUM(ST_Length(f.geom))", count = "COUNT(*)").- id_col
Character vector. Column(s) that uniquely identify each point, used in SELECT and GROUP BY. Default
c("blue_line_key", "downstream_route_measure").- direction
Character.
"upstream"(default) or"downstream".- where
Character or
NULL. Optional SQL predicate to filter features before aggregating (aliasf). Example:"f.accessible IS TRUE"or"f.co_spawning IS TRUE".- to
Character or
NULL. If provided, write results to this table. IfNULL(default), return a data.frame to R.- overwrite
Logical. If
TRUE, droptobefore writing. DefaultTRUE.
Value
If to is provided, conn invisibly (for piping). Otherwise,
a data.frame with one row per point and one column per metric.
Examples
# --- What frs_aggregate output looks like ---
# frs_aggregate returns a data.frame: one row per point, one col per metric.
# This is what you'd get from the Richfield Creek example below:
example_result <- data.frame(
blue_line_key = 360788426,
total_km = 20.1,
spawning_km = 3.2,
rearing_km = 8.7,
n_segments = 52
)
print(example_result)
#> blue_line_key total_km spawning_km rearing_km n_segments
#> 1 360788426 20.1 3.2 8.7 52
# Read: "Upstream of the falls on Richfield Creek, there are 20.1 km of
# stream, of which 3.2 km is coho spawning and 8.7 km is rearing habitat."
if (FALSE) { # \dontrun{
# --- Live DB: full pipeline ending with aggregate ---
# Question: "How much CO habitat is blocked by the Richfield Creek falls?"
conn <- frs_db_conn()
options(fresh.wscode_col = "wscode",
fresh.localcode_col = "localcode")
params <- frs_params(csv = system.file("testdata", "test_params.csv",
package = "fresh"))
# 1. Extract Richfield Creek from fwapg
richfield <- frs_db_query(conn,
"SELECT ST_Union(geom) AS geom
FROM whse_basemapping.fwa_stream_networks_sp
WHERE blue_line_key = 360788426")
conn |>
frs_extract("whse_basemapping.fwa_streams_vw",
"working.demo_agg",
cols = c("linear_feature_id", "blue_line_key",
"downstream_route_measure", "upstream_route_measure",
"wscode", "localcode",
"gradient", "channel_width", "geom"),
aoi = richfield, overwrite = TRUE)
# 2. Break at falls, classify accessibility + CO habitat
DBI::dbExecute(conn, "DROP TABLE IF EXISTS working.demo_agg_breaks")
DBI::dbExecute(conn,
"CREATE TABLE working.demo_agg_breaks AS
SELECT 360788426 AS blue_line_key,
3460.97::double precision AS downstream_route_measure")
co_ranges <- params$CO$ranges$spawn[c("gradient", "channel_width")]
co_rear <- params$CO$ranges$rear[c("gradient", "channel_width")]
conn |>
frs_classify("working.demo_agg", label = "accessible",
breaks = "working.demo_agg_breaks") |>
frs_classify("working.demo_agg", label = "co_spawning",
ranges = co_ranges) |>
frs_classify("working.demo_agg", label = "co_rearing",
ranges = co_rear)
# 3. Aggregate: how much habitat is upstream of the falls (blocked)?
blocked <- frs_aggregate(conn,
points = "working.demo_agg_breaks",
features = "working.demo_agg",
metrics = c(
total_km = "ROUND(SUM(ST_Length(f.geom))::numeric / 1000, 1)",
spawning_km = "ROUND(SUM(CASE WHEN f.co_spawning
THEN ST_Length(f.geom) ELSE 0 END)::numeric / 1000, 1)",
rearing_km = "ROUND(SUM(CASE WHEN f.co_rearing
THEN ST_Length(f.geom) ELSE 0 END)::numeric / 1000, 1)",
n_segments = "COUNT(*)"
),
direction = "upstream")
message("Blocked by Richfield Creek falls:")
message(" Total: ", blocked$total_km, " km")
message(" CO spawning: ", blocked$spawning_km, " km")
message(" CO rearing: ", blocked$rearing_km, " km")
# Clean up
DBI::dbExecute(conn, "DROP TABLE IF EXISTS working.demo_agg")
DBI::dbExecute(conn, "DROP TABLE IF EXISTS working.demo_agg_breaks")
DBI::dbDisconnect(conn)
} # }
