## Download Collar Locations from SQL Database (filtered by species)
<- function(sqltable = "Collars_Locations_ALL",
getSQLData_locs
species){
<- match.arg(species,
species c("Elk","Mule Deer","Pronghorn Antelope","Moose","Wolf","Black Bear","White-tailed Deer",
"Mountain Goat","Rocky Mountain Bighorn Sheep","California Bighorn Sheep","Mountain Lion"),
several.ok = T)
<- DBI::dbConnect(
con ::odbc(),
odbcdriver = "SQL Server",
database = "IFWIS_WildlifeReporting",
uid = "CollarManager",
pwd = #REDACTED,
server = #REDACTED,
port = #REDACTED)
<- DBI::dbReadTable(con,sqltable)
locdata ::dbDisconnect(con)
DBI<- dplyr::filter(locdata,Game %in% species)
sel rm(con,sqltable,locdata)
return(sel)
}
## Download Necropsy data from SQL Database (filtered by species)
getSQLData_nec = function(sqltable = "SAMM_Necropsy", species) {
<- match.arg(species,
species c("Elk","Mule Deer","Pronghorn Antelope","Moose","Wolf","Black Bear","White-tailed Deer",
"Mountain Goat","Rocky Mountain Bighorn Sheep","California Bighorn Sheep","Mountain Lion"),
several.ok = T)
<- DBI::dbConnect(
con ::odbc(),
odbcdriver = "SQL Server",
database = "IFWIS_WildlifeReporting",
uid = "ShinyUserInternal",
pwd = #REDACTED,
server = #REDACTED,
port = #REDACTED)
columns = c("CaptureID","Animal_ID","GameID","FateID","FateDate",
"CensorID","CensorDate","RadFreq","Latitude","Longitude",
"Bnumber","LastLoc","FateDate_OG","CensorDate_OG","NecID",
"BGMR","BlueEarTag")
queries = paste0("SELECT ",
columns, " from ", sqltable)
res = lapply(queries, function(query) {
= DBI::dbGetQuery(con, query)
res
res
})res = dplyr::bind_cols(res)
<- DBI::dbGetQuery(con, "SELECT GAMEID, Game from GAME_PIC_GAME") %>%
lut_game ::filter(Game %in% species) %>%
dplyr::select(GAMEID) %>%
dplyrunique() %>%
unlist()
<- DBI::dbGetQuery(con, "SELECT FateID, FateDesc from SAMM_PIC_FateTypes")
lut_fate
<- dplyr::filter(res,GameID %in% lut_game) %>%
sel ::left_join(.,lut_fate,by="FateID")
dplyr
rm(con,sqltable,res,queries,columns,lut_game,lut_fate)
return(sel)
}
## Download Capture data from SQL Database (filtered by species)
getSQLData_cap = function(sqltable = "SAMM_Capture", species) {
library(dplyr)
library(dbplyr)
<- match.arg(species,
species c("Elk","Mule Deer","Pronghorn Antelope","Moose","Wolf","Black Bear","White-tailed Deer",
"Mountain Goat","Rocky Mountain Bighorn Sheep","California Bighorn Sheep","Mountain Lion"),
several.ok = T)
<- DBI::dbConnect(
con ::odbc(),
odbcdriver = "SQL Server",
database = "IFWIS_WildlifeReporting",
uid = "ShinyUserInternal",
pwd = #REDACTED,
server = #REDACTED,
port = #REDACTED)
tab = tbl(con,sqltable)
columns = colnames(tab)
queries = paste0("SELECT ",
columns, " from ", sqltable)
res = lapply(queries, function(query) {
= DBI::dbGetQuery(con, query)
res
res
})res = dplyr::bind_cols(res)
<- DBI::dbGetQuery(con, "SELECT GAMEID, Game from GAME_PIC_GAME") %>%
lut ::filter(Game %in% species) %>%
dplyr::select(GAMEID) %>%
dplyrunique() %>%
unlist()
<- dplyr::filter(res,GameID %in% lut)
sel
rm(con,sqltable,res,queries,columns,lut)
return(sel)
}
#cap <- getSQLData_cap(species = "Mule Deer")
## Download Vegetation field data from SQL Database
<- function(sqltable = "Veg_fsvm_understory_model_data"){
getSQLData_veg <- DBI::dbConnect(
con ::odbc(),
odbcdriver = "SQL Server",
database = "IFWIS_WildlifeReporting",
uid = "CollarManager",
pwd = #REDACTED,
server = #REDACTED,
port = #REDACTED)
<- DBI::dbReadTable(con,sqltable)
fielddata ::dbDisconnect(con); rm(con,sqltable)
DBIreturn(fielddata)
}
IDFG Regional Projects
Headquarters
While most of my projects for IDFG generally have a statewide-focus, I occasionally help with specific asks from bureau staff.
FSVM predictions for Lodgepole pine distributions
Using the fine scale vegetation model I developed, I was able to provide our staff ecologist with predictions for lodgepole pine to help guide their field sampling efforts.
R Functions (SQL Data Download)
To assist with my regular tasks accessing collar and capture data, I wrote R code to easily access those SQL databases.
Northern Idaho Ground Squirrel Covariates
My expertise with using R for GIS manipulations has been previously called upon to assist with covariate formatting for northern Idaho ground squirrel habitat modeling efforts.
# Load packages
source('B:/Seasonal Range Analysis/Mule Deer/Smokey-Boise/winter/RScripts/instaload_function.R')
instaload(c('sf','terra','exactextractr'))
# Load Grid Shapefile
<- "Q:/RegionMcc/Diane EM/NIDGS/Covariates/2022_GISLayers_for_covariates/grid 100m_entire range_edited 2018 for Tamarack S_2021 S3 Revision.shp"
fp <- sf::st_read(fp)
grid_shp
# List Veg Class Rasters
<- dir("B:/Seasonal Range Analysis/Mule Deer/Covariates/hveg",pattern = "_2020.tif$",full.names = T)
hveg_list
# Load, Clamp, and Stack Rasters
## Function
<- function(x){
load_clamp <- terra::rast(x) %>% terra::clamp(.,lower=1,values=F)
r return(r)
}<- do.call(load_clamp,list(hveg_list))
hveg_stack
# ReProject grid shape (match raster stack)
<- sf::st_transform(grid_shp,terra::crs(hveg_stack))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(hveg_stack,
grid_extract
grid_proj,coverage_area = T,
fun="sum",
force_df =T)
# Rename columns
colnames(grid_extract) <- gsub("sum.","",colnames(grid_extract))
colnames(grid_extract) <- paste0(colnames(grid_extract),"_m2")
# Add to original
<- cbind(grid_shp,grid_extract)
grid_final
# Load Canopy Cover Raster
<- terra::rast("C:/Users/rritson/Documents/Projects/forErin/treecc30.tif")
cancov
# ReProject grid shape (match raster)
<- sf::st_transform(grid_shp,terra::crs(cancov))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(cancov,
grid_extract
grid_proj,coverage_area = T,
fun="mean",
force_df =T)
# Rename column
colnames(grid_extract) <- "NLCD_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
#Save New Grid Shape
::st_write(grid_final,dsn = "Q:/RegionMcc/Diane EM/NIDGS/Covariates/2022_GISLayers_for_covariates/grid 100m_entire range_edited 2018 for Tamarack S_2021 S3 Revision_covs.shp")
sf
#clean-up
::tmpFiles(remove = T)
terrarm(cancov,hveg_list,hveg_stack,grid_shp,grid_proj,grid_extract,grid_final,fp,load_clamp,instaload)
gc()
###
# Load Grid
<- sf::st_read("Q:/RegionMcc/Diane EM/NIDGS/Covariates/2022_GISLayers_for_covariates/grid 100m_entire range_edited 2018 for Tamarack S_2021 S3 Revision_covs.shp")
grid_final
# Load remaining covariates
## Soil Bulk Density
<- terra::rast("Q:/RegionMcc/Diane EM/NIDGS/Covariates/EnvironmentalData/Soils/POLARIS/bulkdens")
bulkdens
# ReProject grid shape (match raster)
<- sf::st_transform(grid_final,terra::crs(bulkdens))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(bulkdens,
grid_extract
grid_proj,coverage_area = T,
fun="mean",
force_df =T)
# Rename column
colnames(grid_extract) <- "BulkDensity_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
## Percent Silt
<- terra::rast("Q:/RegionMcc/Diane EM/NIDGS/Covariates/EnvironmentalData/Soils/POLARIS/siltperc")
siltperc
# ReProject grid shape (match raster)
<- sf::st_transform(grid_final,terra::crs(siltperc))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(siltperc,
grid_extract
grid_proj,coverage_area = T,
fun="mean",
force_df =T)
# Rename column
colnames(grid_extract) <- "PercSilt_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
## Soil Depth
<- terra::rast("Q:/RegionMcc/Diane EM/NIDGS/Covariates/EnvironmentalData/Soils/POLARIS/resdep")
resdep
# ReProject grid shape (match raster)
<- sf::st_transform(grid_final,terra::crs(resdep))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(resdep,
grid_extract
grid_proj,coverage_area = T,
fun="mean",
force_df =T)
# Rename column
colnames(grid_extract) <- "SoilDepth_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
#install.packages('spatialEco')
require(spatialEco)
<- terra::rast("C:/Users/rritson/Documents/Projects/forErin/DEM10M_1.tif")
dem ## CLIP IS TOO SMALL!!!!!
## Aspect
<- terra::terrain(dem,"aspect")
asp
# ReProject grid shape (match raster)
<- sf::st_transform(grid_final,terra::crs(asp))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(asp,
grid_extract
grid_proj,coverage_area = T,
fun='mean',
force_df =T)
# Rename column
colnames(grid_extract) <- "Aspect_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
## Heat Load Index
<- spatialEco::hli(dem)
hli
# ReProject grid shape (match raster)
<- sf::st_transform(grid_final,terra::crs(hli))
grid_proj
# Extract coverage areas
<- exactextractr::exact_extract(hli,
grid_extract
grid_proj,coverage_area = T,
fun='mean',
force_df =T)
# Rename column
colnames(grid_extract) <- "HEAT_mean"
# Add to original
<- cbind(grid_final,grid_extract)
grid_final
$AspectClass <- ifelse(23 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 68,"Northeast",
grid_finalifelse(69 <= grid_final$Aspect_mean & grid_final$Aspect_mean<= 112,"East",
ifelse(113 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 158,"Southeast",
ifelse(159 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 202,"South",
ifelse(203 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 248,"Southwest",
ifelse(249 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 292,"West",
ifelse(293 <= grid_final$Aspect_mean & grid_final$Aspect_mean <= 338,"Northwest","North")))))))
#Save New Grid Shape
::st_write(grid_final,dsn = "Q:/RegionMcc/Diane EM/NIDGS/Covariates/2022_GISLayers_for_covariates/grid 100m_entire range_edited 2018 for Tamarack S_2021 S3 Revision_covs2.shp")
sf
#clean-up
::tmpFiles(remove = T)
terrarm(grid_proj,grid_extract,grid_final,asp,dem,resdep,siltperc,bulkdens,hli)
gc()
MTBS Fire Covariates
Recently, I developed code for manipulating fire data from MTBS into covariate rasters relevant to the FSVM and ungulate seasonal range modeling efforts.
# Load packages
require(sf)
require(terra)
require(foreign)
require(dplyr)
require(stringr)
require(lubridate)
### Set-up ------------------------------------------
## significant digits (7 digit coordinate + 10 digits after decimal (for nanometers) = 17 significant digits)
if(options()$digits != 17){
options(digits = 17)
}## 'terra' options
#'INT2S'
::terraOptions(datatype = 'INT2S') # same data type Brendan used, default in 'terra' is 'FLT4S'
terra::terraOptions(tolerance = 1e-10)
terra::terraOptions()
terra## proj4strings
#WGS84 Longitude and Latitude
= "+proj=longlat +datum=WGS84 +no_defs +ellps=WGS84 +towgs84=0,0,0"
lonlat #Idaho Transverse Mercator
#idtm = "+proj=tmerc +lat_0=42 +lon_0=-114 +k=0.9996 +x_0=2500000 +y_0=1200000 +datum=NAD83 +units=m +no_defs +ellps=GRS80 +towgs84=0,0,0"
<- "epsg:8826"
idtm
#Load base grid
<- terra::rast('B:/Covariates/base_grid/idaho_buffer_100km_30m.tif')
base ::res(base)
terra::crs(base)
terra<- terra::project(base, idtm)
base
#Load Idaho state boundary
<- sf::st_read("B:/GIS_ReferenceLayers/ID_StateBoundary/IDTM", "IdahoBoundary_IDTM") %>%
idaho ::vect(.) %>%
terra::project(.,base) #ensure projections match
terra::plot(terra::ext(base))
terra::plot(idaho, add = T)
terra
#Create bounding box from base grid
<- base %>%
bbox ::st_bbox(.,crs = sf::st_crs(base)) %>%
sf::st_as_sfc(.) %>%
sf::st_as_sf(.) %>%
sf::mutate(PolyID = "NDVI_30m_Idaho_100kmBuff") %>%
dplyr::vect(.)
terra
# Load MTBS perimeter file
## Download at: https://mtbs.gov/direct-download; Burned Areas Boundaries Dataset
<- sf::st_read("C:/Users/rritson/Documents/Covariates/Fire/MTBS_perimeter_shape/mtbs_perims_DD.shp",quiet=T) %>%
fire ::st_transform(.,idtm) %>%
sf::select(Event_ID,Incid_Name,Incid_Type,BurnBndAc,Ig_Date,Comment) %>%
dplyr::rowwise(.) %>%
dplyr::mutate(Year = stringr::str_split_fixed(Ig_Date,"-",3)[[1]],
dplyrMonth = stringr::str_split_fixed(Ig_Date,"-",3)[[2]],
Day = stringr::str_split_fixed(Ig_Date,"-",3)[[3]]) %>%
::select(Event_ID,Incid_Name,Incid_Type,BurnBndAc,Year,Month,Day,Comment) %>%
dplyr::vect(.) %>%
terra::crop(.,bbox) %>%
terra::st_as_sf(.) #Important for filtering!!!
sf
# Create Binary Burned Rasters
## Filter by Year
<- 2000:2021
yrs for(yr in yrs){
print(paste0("Calculating ",yr,"..."))
### since 1984
print(paste("All Years"))
<- fire %>%
fire_yr ::filter(Year <= yr) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="max",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "Burned"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/Burned_allyrs_",yr,".tif"))
terra
### Last 10 yrs
print(paste("Last Ten Years"))
<- fire %>%
fire_yr ::filter(Year <= yr & Year >= (yr-10)) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="max",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "Burned"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/Burned_last10_",yr,".tif"))
terra
### Only Year of
print(paste("Year of Only"))
<- fire %>%
fire_yr ::filter(Year == yr) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="max",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "Burned"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/Burned_yrof_",yr,".tif"))
terra
}
## Frequency of Fire (N unique)
<- 2000:2021
yrs for(yr in yrs){
print(paste0("Calculating ",yr,"..."))
### since 1984
print(paste("All Years"))
<- fire %>%
fire_yr ::filter(Year <= yr) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="sum",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "N_fires"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/FireFrequency_allyrs_",yr,".tif"))
terra
### Last 10 yrs
print(paste("Last Ten Years"))
<- fire %>%
fire_yr ::filter(Year <= yr & Year >= (yr-10)) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="sum",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "N_fires"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/FireFrequency_last10_",yr,".tif"))
terra
### Only Year of
print(paste("Year of Only"))
<- fire %>%
fire_yr ::filter(Year == yr) %>%
dplyr::mutate(Burned = 1) %>%
dplyr::select(Burned) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,fun="sum",background=0,touches=F,na.rm=T,update=F,by=NULL,cover=F)
fire_rast names(fire_rast) <- "N_fires"
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/FireFrequency_yrof_",yr,".tif"))
terra
}
## Time since last fire (Year)
<- 2000:2021
yrs for(yr in yrs){
print(paste0("Calculating ",yr,"..."))
## since 1984
print(paste("All Years"))
<- fire %>%
fire_yr ::filter(Year <= yr) %>%
dplyr#dplyr::rowwise(.) %>%
::mutate(TSF = yr-as.numeric(Year)) %>%
dplyr::select(TSF,geometry) #%>%
dplyr#dplyr::ungroup(.) %>%
#terra::vect(.)
<- terra::rasterize(fire_yr,base,"TSF",fun=min,background=-9999,touches=F,na.rm=T,update=F,by=NULL,cover=F) #9999 never burned or not burned within defined period
fire_rast names(fire_rast) <- "TSF" #time since last fire (years)
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/YearSinceFire_allyrs_",yr,".tif"))
terra
## Last 10 years
print(paste("Last Ten Years"))
<- fire %>%
fire_yr ::filter(Year <= yr & Year >= (yr-10)) %>%
dplyr::rowwise(.) %>%
dplyr::mutate(TSF = yr-as.numeric(Year)) %>%
dplyr::select(TSF) %>%
dplyr::vect(.)
terra<- terra::rasterize(fire_yr,base,"TSF",fun=min,background=-9999,touches=F,na.rm=T,update=F,by=NULL,cover=F) #9999 never burned or not burned within defined period
fire_rast names(fire_rast) <- "TSF" #time since last fire (years)
::writeRaster(fire_rast,paste0("E:/Seasonal_range_covars/fire/YearSinceFire_last10_",yr,".tif"),overwrite=T)
terra }
Region 5
Being stationed in the regional office, I occasionally assist staff with GIS-related questions and tasks. I have also helped out with field tasks including mule deer drive nets, pronghorn surveys, and fisheries.
Sterling WMA Spatially Balanced Random Sampling
Generalized random tessellation stratified (GRTS) algorithm
Blackfoot Reservoir Lowland Lake Survey Sites
R code: fishnetR
<- function(shp,cell_size,n,stratify=TRUE,seed=1){
fishnetR require(dplyr)
# Create grid (fishnet)
<- sf::st_make_grid(shp, cellsize = cell_size, what = "polygons", square = T) %>%
grid ::vect(.) %>%
terra::crop(.,terra::vect(shp)) %>%
terra::st_as_sf(.) %>%
sf::st_cast(.,"POLYGON") %>%
sf::mutate(id = seq(1,nrow(.), by=1))
dplyr
#Calculate Stratas
<- rep(c(1:n),each=floor(nrow(grid)/n))
stratas
# randomly assign remainder
<- sample.int(n,nrow(grid)%%n,F)
extra
# combine strata
<- sort(c(stratas,extra))
stratas
# Set stratas
<- dplyr::mutate(grid,strata = as.factor(stratas))
grid
#Stratify Random Sample
set.seed(seed)
if(stratify){
=sample(1:1000,1)
irepeat{
= i+1
iset.seed(i)
<- sf::st_drop_geometry(grid)
spx if(!inherits(spx[,"strata"], "factor"))
"strata"] <- factor(spx[,"strata"])
spx[,$REP <- NA
spx=1
reps=1
nn<- list()
results for(j in levels(spx[, "strata"])) {
<- spx[spx[,"strata"] == j,]
d $rowname <- rownames(d)
dif(nrow(d) > n) {
for (i in 1:reps) {
<- lapply(1, function(ij) {
s sample(1:nrow(d), nn),]})
d[1]]$REP <- i
s[[paste(j,i,sep="_")]] <-s[[1]]
results[[
}else {
} $REP <- 1
dpaste(j,i,sep="_")]] <- d
results[[
}
}
results<- do.call(rbind, results)
results =F
replaceif(!replace){
if(any(duplicated(results$rowname))){
<- results[-which(duplicated(results$rowname)),]
results
}
}<- stats::na.omit(results[,c("rowname","REP")])
results <- merge(grid, results, by.y="rowname", by.x = 'row.names',
results all.x = FALSE, all.y = TRUE)
<- results %>%
strat_rand_samp ::st_as_sf(.)
sfif(any(sf::st_relate(strat_rand_samp, pattern = "F***1****",sparse=F)==T)==F && nrow(strat_rand_samp)==21){
break
}
}#return(strat_rand_samp)
return(list(strat_rand_samp = strat_rand_samp, grid = grid))
#Simple Random Sample
else{
}<- sample.int(nrow(grid), size = n, replace=F)
randsamp <- grid[randsamp,]
locs #sf::st_write(locs,filepath) #write grids to filepath (forthcoming)
return(locs)
} }