This vignette will demonstrate how you can use bcdata
to access and explore British Columbia silviculture data.
Silviculture data for British Columbia are largely collected and stored through the Reporting Silviculture Updates and Land Status Tracking System (RESULTS) database—including information on the management of openings, disturbances, silviculture activities and obligation declarations as required by the Forest and Range Practices Act. RESULTS data sets are publically available through the B.C. Data Catalogue under the Open Government Licence - British Columbia.
Western larch has been identified as a tree species that will be well-adapted to projected future climates in northern British Columbia. In 2013, forest policy was developed that allowed foresters to plant western larch outside of its natural range as a climate change adaptation silviculture measure.
Let’s use the bcdata
package to search, retrieve and explore the RESULTS silviculture data and answer this question.
To start, let’s load the bcdata
package. We will also load the dplyr
and ggplot2
packages to help us work with the data. You can learn more about the dplyr
package here and the ggplot2
package here:
We can gather the data we need to answer our question using the RESULTS - silviculture forest cover dataset. First, let’s take a look at the metadata record using bcdc_get_record()
:
# Get the metadata using the human-readable record name
bcdc_get_record("results-forest-cover-silviculture")
#> B.C. Data Catalogue Record: RESULTS - Forest Cover Silviculture
#>
#> Name: results-forest-cover-silviculture (ID: 258bb088-4113-47b1-b568-ce20bd64e3e3 )
#> Permalink: https://catalogue.data.gov.bc.ca/dataset/258bb088-4113-47b1-b568-ce20bd64e3e3
#> Sector: Natural Resources
#> Licence: Open Government Licence - British Columbia
#> Type: Geographic
#> Last Updated: 2020-05-25
#>
#> Description: RESULTS opening's forest cover poylgons with silviculture component provided.
#> Current forest cover subimssion into RESULTS must contain attribute and map
#> information. However, there are historical forest cover polygon infomration where
#> maps are not available. Forest Cover is provided at three critical milestones of at
#> harvesting, at regeneration, and at free growing. This is a part o fthe
#> Silviculture and Land Status Tracking dataset, which includes tracking achievement
#> of silviculture obligations on Crown Land
#>
#> Resources: (3)
#> # A tibble: 3 x 8
#> name url id format ext package_id location bcdata_available
#> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <lgl>
#> 1 BC Geog… https://c… 92f845… other "" 258bb088-4… bcgeogr… FALSE
#> 2 WMS get… https://o… 57670a… wms "" 258bb088-4… bcgeogr… TRUE
#> 3 KML Net… https://o… d45a82… kml "kml" 258bb088-4… bcgeogr… FALSE
#>
#> You can access the 'Resources' data frame using bcdc_tidy_resources()
We see that this is a Web Service-enabled geospatial data set—the list of data resources includes WMS getCapabilities request
—so we can query and retrieve this geospatial data set using bcdc_query_geodata()
:
# Query the data using the permanent ID of the record to guard against name changes
bcdc_query_geodata("258bb088-4113-47b1-b568-ce20bd64e3e3")
#> Querying 'results-forest-cover-silviculture' record
#> ● Using collect() on this object will return 873108 features and 159 fields
#> ● At most six rows of the record are printed here
#> ────────────────────────────────────────────────────────────────────────────────
#> Simple feature collection with 6 features and 159 fields
#> geometry type: MULTIPOLYGON
#> dimension: XY
#> bbox: xmin: 1147890 ymin: 676633.7 xmax: 1411085 ymax: 1083545
#> CRS: 3005
#> # A tibble: 6 x 160
#> id FOREST_COVER_ID STOCKING_STANDA… OPENING_ID STANDARDS_UNIT_…
#> <chr> <int> <int> <int> <chr>
#> 1 WHSE… 3994018 1805957 1486231 2
#> 2 WHSE… 3994007 NA 1248495 <NA>
#> 3 WHSE… 3993995 2263260 1728926 1
#> 4 WHSE… 3994067 NA 1120935 <NA>
#> 5 WHSE… 3994009 1404558 1248495 A
#> 6 WHSE… 3994057 1211894 1120935 B
#> # … with 155 more variables: SILV_POLYGON_NUMBER <chr>,
#> # SILV_POLYGON_AREA <dbl>, SILV_POLYGON_NET_AREA <dbl>,
#> # SILV_NON_MAPPED_AREA <int>, STOCKING_STATUS_CODE <chr>,
#> # STOCKING_TYPE_CODE <chr>, STOCKING_CLASS_CODE <chr>,
#> # SILV_RESERVE_CODE <chr>, SILV_RESERVE_OBJECTIVE_CODE <chr>,
#> # TREE_COVER_PATTERN_CODE <chr>, REENTRY_YEAR <chr>, REFERENCE_YEAR <int>,
#> # SITE_INDEX <int>, SITE_INDEX_SOURCE_CODE <chr>, BGC_ZONE_CODE <chr>,
#> # BGC_SUBZONE_CODE <chr>, BGC_VARIANT <chr>, BGC_PHASE <chr>,
#> # BEC_SITE_SERIES <chr>, BEC_SITE_TYPE <chr>, BEC_SERAL <chr>,
#> # IS_SILV_IMPLIED_IND <chr>, FOREST_COVER_SILV_TYPE <chr>,
#> # S_FOREST_COVER_LAYER_ID <int>, S_TOTAL_STEMS_PER_HA <chr>,
#> # S_TOTAL_WELL_SPACED_STEMS_HA <int>, S_WELL_SPACED_STEMS_PER_HA <int>,
#> # S_FREE_GROWING_STEMS_PER_HA <int>, S_CROWN_CLOSURE_PERCENT <chr>,
#> # S_BASAL_AREA <chr>, S_SPECIES_CODE_1 <chr>, S_SPECIES_PERCENT_1 <int>,
#> # S_SPECIES_AGE_1 <int>, S_SPECIES_HEIGHT_1 <dbl>, S_SPECIES_CODE_2 <chr>,
#> # S_SPECIES_PERCENT_2 <int>, S_SPECIES_AGE_2 <chr>, S_SPECIES_HEIGHT_2 <chr>,
#> # S_SPECIES_CODE_3 <chr>, S_SPECIES_PERCENT_3 <int>, S_SPECIES_CODE_4 <chr>,
#> # S_SPECIES_PERCENT_4 <chr>, S_SPECIES_CODE_5 <chr>,
#> # S_SPECIES_PERCENT_5 <chr>, S_MORE_SPECIES_EXIST_IND <chr>,
#> # S_SILV_LABEL <chr>, S1_FOREST_COVER_LAYER_ID <int>,
#> # S1_TOTAL_STEMS_PER_HA <int>, S1_TOTAL_WELL_SPACED_STEMS_HA <int>,
#> # S1_WELL_SPACED_STEMS_PER_HA <int>, S1_FREE_GROWING_STEMS_PER_HA <int>,
#> # S1_CROWN_CLOSURE_PERCENT <int>, S1_BASAL_AREA <chr>,
#> # S1_SPECIES_CODE_1 <chr>, S1_SPECIES_PERCENT_1 <int>,
#> # S1_SPECIES_AGE_1 <int>, S1_SPECIES_HEIGHT_1 <int>, S1_SPECIES_CODE_2 <chr>,
#> # S1_SPECIES_PERCENT_2 <chr>, S1_SPECIES_AGE_2 <chr>,
#> # S1_SPECIES_HEIGHT_2 <chr>, S1_SPECIES_CODE_3 <chr>,
#> # S1_SPECIES_PERCENT_3 <chr>, S1_SPECIES_CODE_4 <chr>,
#> # S1_SPECIES_PERCENT_4 <chr>, S1_SPECIES_CODE_5 <chr>,
#> # S1_SPECIES_PERCENT_5 <chr>, S1_MORE_SPECIES_EXIST_IND <chr>,
#> # S1_SILV_LABEL <chr>, S2_FOREST_COVER_LAYER_ID <int>,
#> # S2_TOTAL_STEMS_PER_HA <int>, S2_TOTAL_WELL_SPACED_STEMS_HA <int>,
#> # S2_WELL_SPACED_STEMS_PER_HA <int>, S2_FREE_GROWING_STEMS_PER_HA <int>,
#> # S2_CROWN_CLOSURE_PERCENT <int>, S2_BASAL_AREA <chr>,
#> # S2_SPECIES_CODE_1 <chr>, S2_SPECIES_PERCENT_1 <int>,
#> # S2_SPECIES_AGE_1 <int>, S2_SPECIES_HEIGHT_1 <int>, S2_SPECIES_CODE_2 <chr>,
#> # S2_SPECIES_PERCENT_2 <chr>, S2_SPECIES_AGE_2 <chr>,
#> # S2_SPECIES_HEIGHT_2 <chr>, S2_SPECIES_CODE_3 <chr>,
#> # S2_SPECIES_PERCENT_3 <chr>, S2_SPECIES_CODE_4 <chr>,
#> # S2_SPECIES_PERCENT_4 <chr>, S2_SPECIES_CODE_5 <chr>,
#> # S2_SPECIES_PERCENT_5 <chr>, S2_MORE_SPECIES_EXIST_IND <chr>,
#> # S2_SILV_LABEL <chr>, S3_FOREST_COVER_LAYER_ID <int>,
#> # S3_TOTAL_STEMS_PER_HA <int>, S3_TOTAL_WELL_SPACED_STEMS_HA <int>,
#> # S3_WELL_SPACED_STEMS_PER_HA <int>, S3_FREE_GROWING_STEMS_PER_HA <int>,
#> # S3_CROWN_CLOSURE_PERCENT <int>, S3_BASAL_AREA <chr>,
#> # S3_SPECIES_CODE_1 <chr>, …
This query shows that this data set has over 850,000 features and over 150 fields. Each feature is a treatment unit within a harvested opening, and contains information on the leading five tree species that are present in each treatment unit, including stems per hectare, age, and height.
Note that we have only queried the data set so far—the data set would be too large (~1GB) to download efficiently. So, let’s use filter()
with bcdc_query_geodata()
to refine our query before we collect the data and import it into R.
To address our question, we need the treatment data (1) from the Prince George Natural Resource District and (2) that contain western larch.
First, we can use the bcdata
package to download the spatial boundary for the Prince George Natural Resource District—DPG
is the ORG_UNIT
for Prince George Natural Resource District:
## Create a spatial feature object named dpg
dpg <- bcdc_query_geodata("natural-resource-nr-district") %>%
filter(ORG_UNIT=="DPG") %>% # filter for Prince George Natural Resource District
collect() # and collect the data
Let’s plot this spatial object and double check we have we what we need:
Now we have a spatial object that we can use as a bounding box to filter and download records in the RESULTS - silviculture layer from the Prince George Natural Resource District.
We only need to download the treatments that have western larch planted. We can use the bcdc_describe_feature()
helper function to examine the column names and types of the layer. In this case, we want to keep rows where the five S_SPECIES_CODE_*
columns contain "LW"
, the code for western larch.
# Make a vector of tree species we are interested in
# (in this case only LW for western larch)
spp_list = c("LW")
# Query and filter the data layer
trees_dpg <-
bcdc_query_geodata("258bb088-4113-47b1-b568-ce20bd64e3e3") %>%
filter(INTERSECTS(dpg)) %>% #filter for records that are within the DPG boundary
filter(
S_SPECIES_CODE_1 %in% spp_list | #filter for LW records
S_SPECIES_CODE_2 %in% spp_list |
S_SPECIES_CODE_3 %in% spp_list |
S_SPECIES_CODE_4 %in% spp_list |
S_SPECIES_CODE_5 %in% spp_list
) %>%
collect() #collect/download the data
Let’s look at the dimensions of this now much more manageable data object we have downloaded from the B.C. Data Catalogue:
We can see there are 160 treatment units planted with western larch, and we can make a quick map of these harvested openings for the Prince George Natural Resource District:
trees_dpg %>%
ggplot() +
geom_sf() +
geom_sf(data = dpg, fill = NA) + #add the DPG spatial boundary
theme_minimal()
We can also create some quick descriptive summaries of the data, treating the geospatial attribute table as a data frame in R, and answer our original question—how much western larch has been planted in the Prince George Natural Resource District?
trees_dpg %>%
mutate(age = 2020 - REFERENCE_YEAR + S_SPECIES_AGE_1) %>% #create a plantation age column
ggplot() + #start a plot
aes(x = age, y = FEATURE_AREA_SQM/10000) + #convert feature area to hectares
geom_bar(stat = "sum") +
scale_x_continuous(name = "Stand Age (years)",
limits = c(2, 30),
breaks = seq(from = 5, to = 30, by = 5)) +
labs(y = "Sum Treatment Unit Area (ha)",
title = "Area Planted with Western Larch by Stand Age\nin Prince George Natural Resource District",
caption = paste0("Data sourced from the B.C. Data Catalogue\n on ",
Sys.Date(),
" using the bcdata R package")) +
theme_minimal() +
theme(legend.position = "none")
We can download British Columbia biogeoclimatic (BEC) data from the B.C. Data Catalogue using bcdata
and join to our existing trees_dpg
geospatial dataset using the st_join
function from the sf
package. You can learn more about sf
here.
library(sf) #load the sf package
# Load the BEC data for Prince George Natural Resource District
bgc_dpg <- bcdc_query_geodata("WHSE_FOREST_VEGETATION.BEC_BIOGEOCLIMATIC_POLY") %>%
filter(BBOX(dpg, crs = `EPSG:3005`)) %>% #note filtering with a BoundingBox
collect()
# Join the BEC data with our tress_dpg geospatial data set
trees_bec_dpg <- trees_dpg %>%
st_join(bgc_dpg[, "MAP_LABEL"]) #join BEC data for each polygon
Now, we can summarize the area planted with western larch by biogeoclimatic unit:
trees_bec_dpg %>%
group_by(MAP_LABEL) %>% # group polygons by biogeoclimatic unit
summarise(Area = sum(FEATURE_AREA_SQM)/10000) %>%
ggplot() +
aes(x = MAP_LABEL, y = Area) +
geom_col() +
labs(y = "Sum Treatment Unit Area (ha)",
x = "Biogeoclimatic Unit",
title = "Area Planted with Western Larch by Biogeoclimatic Unit\nin Prince George Natural Resource District",
caption = paste0("Data sourced from the B.C. Data Catalogue\n on ",
Sys.Date(),
" using the bcdata R package")) +
theme_minimal() +
theme(legend.position = "none")