NEON Woody Vegetation Visualization
Laura Puckett
11/29/2021
A simple project to download, organize, and interactively view NEON data. This was a fun project to get practice accesing data through APIs and building interactive apps.
My code for this project is shown in a reproducible example below.
Part 1. Download Data
Load Libraries
R version: 4.1.2
library(neonUtilities); library(ggplot2)
library(dplyr); library(shinyr); library(shinythemes)
Download Data using NEON APIlibrary(neonUtilities);
# load my neon token as an object called NEON_TOKEN
source('./neon_token.R')
# instructions for getting a NEON API token can be found here: https://www.neonscience.org/resources/learning-hub/tutorials/neon-api-tokens-tutorial
veglist = loadByProduct(dpID="DP1.10098.001",
site = "all",
package = "basic",
check.size = F,
token = NEON_TOKEN)
saveRDS(veglist, './veglist.Rdata')
Part 2. Organize Data
Load datasets of interest and select columns of interestveglist = readRDS('./veglist.Rdata')
veg_ind = veglist$vst_apparentindividual %>%
dplyr::select(siteID, plotID, height, individualID, plantStatus,
stemDiameter, date, eventID)
veg_loc = veglist$vst_mappingandtagging %>%
dplyr::select(domainID, siteID, plotID, individualID, taxonID, scientificName) %>%
unique()
plot_info = veglist$vst_perplotperyear %>%
select(eventID, siteID, plotID, plotType) %>%
unique()
rm(veglist) # unload the large file now that it's no longer needed
Join Datasetsveg = veg_ind %>%
inner_join(veg_loc, by = c("individualID", "siteID", "plotID")) %>%
inner_join(plot_info, by = c("siteID", "plotID", "eventID"))
veg %>% head()
## siteID plotID height individualID plantStatus
## 1 BART BART_044 5.6 NEON.PLA.D01.BART.05332 Live, disease damaged
## 2 BART BART_037 11.5 NEON.PLA.D01.BART.05273 Live, disease damaged
## 3 BART BART_037 1.8 NEON.PLA.D01.BART.05262 Live, disease damaged
## 4 BART BART_044 0.8 NEON.PLA.D01.BART.05424 Live
## 5 BART BART_044 10.4 NEON.PLA.D01.BART.05415 Live, disease damaged
## 6 BART BART_044 1.1 NEON.PLA.D01.BART.05319 Live
## stemDiameter date eventID domainID taxonID
## 1 5.8 2015-08-26 vst_BART_2015 D01 FAGR
## 2 10.3 2015-08-26 vst_BART_2015 D01 FAGR
## 3 1.6 2015-08-26 vst_BART_2015 D01 FAGR
## 4 1.4 2015-08-26 vst_BART_2015 D01 TSCA
## 5 12.5 2015-08-26 vst_BART_2015 D01 FAGR
## 6 1.2 2015-08-26 vst_BART_2015 D01 PICEA
## scientificName plotType
## 1 Fagus grandifolia Ehrh. tower
## 2 Fagus grandifolia Ehrh. tower
## 3 Fagus grandifolia Ehrh. tower
## 4 Tsuga canadensis (L.) Carrière tower
## 5 Fagus grandifolia Ehrh. tower
## 6 Picea sp. tower
Filter Dataveg = veg %>%
# filter for Live trees
filter(substr(plantStatus, 1,4) == "Live") %>%
# filter for tree measurements (which start at 10cm)
filter(stemDiameter > 10) %>%
filter(is.na(height) == F & is.na(stemDiameter) == F) %>%
# remove outliers
group_by(taxonID) %>%
mutate(height_lower = boxplot(height, plot=FALSE)$stats[1],
height_upper = boxplot(height, plot=FALSE)$stats[5],
diam_lower = boxplot(stemDiameter, plot=FALSE)$stats[1],
diam_upper = boxplot(stemDiameter, plot=FALSE)$stats[5]) %>%
filter(height > height_lower & height < height_upper,
stemDiameter > diam_lower & stemDiameter < diam_upper) %>%
dplyr::select(-height_lower, -height_upper, -diam_lower, -diam_upper) %>%
ungroup()
# Select columns
veg = veg %>%
dplyr::select(siteID, stemDiameter, height, plantStatus, scientificName, taxonID, date, individualID)
Get the 20 Most Commmon Species# Find top 20 species by observation count
species = veg %>%
group_by(taxonID, scientificName) %>%
summarize(obs_count = n()) %>%
arrange(desc(obs_count)) %>%
head(20) %>%
select(taxonID, scientificName) %>%
ungroup() %>%
mutate(num = row_number()) %>%
as.data.frame()
Write Output Files for Shiny AppsaveRDS(veg, './veg_data_for_shiny.Rdata')
saveRDS(species, './species.Rdata')
Part 3. The Shiny app
Server Functionserver = function(input, output) {
selection = reactive({
as.numeric(input$optionNum)
})
selected_data <- reactive({
df <- veg %>%
filter(taxonID == species$taxonID[as.numeric(input$optionNum)]) %>%
dplyr::select(individualID, siteID,scientificName, plantStatus, date, stemDiameter, height)
if(!input$Live){
df = df %>% filter(plantStatus != "Live")
}
if(!input$Live_DD){
df = df %>% filter(plantStatus != "Live, disease damaged")
}
if(!input$Live_PD){
df = df %>% filter(plantStatus != "Live, physically damaged")
}
if(!input$Live_BB){
df = df %>% filter(plantStatus != "Live, broken bole")
}
if(!input$Live_ID){
df = df %>% filter(plantStatus != "Live, insect damaged")
}
if(!input$Live_OD){
df = df %>% filter(plantStatus != "Live, other damage")
}
print(df)
df
})
output$table <- DT::renderDataTable({
table <- selected_data()
})
output$plot1 <- renderPlot({
ggplot(data = selected_data(),
aes(x = stemDiameter, y = height)) +
theme_bw() +
geom_point(aes(color = siteID), alpha = 0.4) +
geom_smooth(color = "black",size = 0.5, se = F) +
xlab("Stem Diameter [cm]") +
ylab("Tree Height [m]") +
# ggtitle(paste("Selected Species:",
# species$scientificName[selection()])) +
labs(colour = "NEON Site ID")+
theme(legend.position = "right",
axis.title = element_text(size = 16))
})
output$result <- renderText({
paste("You have selected ", species$scientificName[selection()])
})
}
User Interface Functionui = fluidPage(
theme = shinytheme("readable"),
h3("NEON Woody Plant Vegetation Structure Data"),
p("This app allows for quick visualization of tree height and diameter data for the 20 most common species in the NEON woody vegetation structure dataset. The data have been filtered to remove dead trees and obvious outliers for height and diameter. "),
HTML("<p style='color:#808080'>NEON (National Ecological Observatory Network). Woody plant vegetation structure, RELEASE-2021 (DP1.10098.001). https://doi.org/10.48443/e3qn-xw47. Dataset accessed from https://data.neonscience.org on November 24, 2021 </p>"),
p("\n"),
fluidRow(column(width = 12, selectInput(inputId = "optionNum",
label = "Choose a Species Group",
choices = input_options,
selected = 1))),
fluidRow(column(width = 1, checkboxInput("Live", "Live", TRUE)),
column(width = 2, checkboxInput("Live_DD", "Live, disease damaged", TRUE,)),
column(width = 2, checkboxInput("Live_PD", "Live, physically damaged", TRUE)),
column(width = 2, checkboxInput("Live_BB", "Live, broken bole", TRUE)),
column(width = 2, checkboxInput("Live_ID", "Live, insect damaged", TRUE)),
column(width = 2, checkboxInput("Live_OD", "Live, other damage", TRUE))),
mainPanel(tabsetPanel(type = "tabs",
tabPanel(title ="Plot", plotOutput('plot1')),
tabPanel("Data Table", DT::dataTableOutput('table')))
)
)
App Setup# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
Run the AppshinyApp(ui = ui, server = server)
library(neonUtilities);
# load my neon token as an object called NEON_TOKEN
source('./neon_token.R')
# instructions for getting a NEON API token can be found here: https://www.neonscience.org/resources/learning-hub/tutorials/neon-api-tokens-tutorial
veglist = loadByProduct(dpID="DP1.10098.001",
site = "all",
package = "basic",
check.size = F,
token = NEON_TOKEN)
saveRDS(veglist, './veglist.Rdata')
veglist = readRDS('./veglist.Rdata')
veg_ind = veglist$vst_apparentindividual %>%
dplyr::select(siteID, plotID, height, individualID, plantStatus,
stemDiameter, date, eventID)
veg_loc = veglist$vst_mappingandtagging %>%
dplyr::select(domainID, siteID, plotID, individualID, taxonID, scientificName) %>%
unique()
plot_info = veglist$vst_perplotperyear %>%
select(eventID, siteID, plotID, plotType) %>%
unique()
rm(veglist) # unload the large file now that it's no longer needed
Join Datasetsveg = veg_ind %>%
inner_join(veg_loc, by = c("individualID", "siteID", "plotID")) %>%
inner_join(plot_info, by = c("siteID", "plotID", "eventID"))
veg %>% head()
## siteID plotID height individualID plantStatus
## 1 BART BART_044 5.6 NEON.PLA.D01.BART.05332 Live, disease damaged
## 2 BART BART_037 11.5 NEON.PLA.D01.BART.05273 Live, disease damaged
## 3 BART BART_037 1.8 NEON.PLA.D01.BART.05262 Live, disease damaged
## 4 BART BART_044 0.8 NEON.PLA.D01.BART.05424 Live
## 5 BART BART_044 10.4 NEON.PLA.D01.BART.05415 Live, disease damaged
## 6 BART BART_044 1.1 NEON.PLA.D01.BART.05319 Live
## stemDiameter date eventID domainID taxonID
## 1 5.8 2015-08-26 vst_BART_2015 D01 FAGR
## 2 10.3 2015-08-26 vst_BART_2015 D01 FAGR
## 3 1.6 2015-08-26 vst_BART_2015 D01 FAGR
## 4 1.4 2015-08-26 vst_BART_2015 D01 TSCA
## 5 12.5 2015-08-26 vst_BART_2015 D01 FAGR
## 6 1.2 2015-08-26 vst_BART_2015 D01 PICEA
## scientificName plotType
## 1 Fagus grandifolia Ehrh. tower
## 2 Fagus grandifolia Ehrh. tower
## 3 Fagus grandifolia Ehrh. tower
## 4 Tsuga canadensis (L.) Carrière tower
## 5 Fagus grandifolia Ehrh. tower
## 6 Picea sp. tower
Filter Dataveg = veg %>%
# filter for Live trees
filter(substr(plantStatus, 1,4) == "Live") %>%
# filter for tree measurements (which start at 10cm)
filter(stemDiameter > 10) %>%
filter(is.na(height) == F & is.na(stemDiameter) == F) %>%
# remove outliers
group_by(taxonID) %>%
mutate(height_lower = boxplot(height, plot=FALSE)$stats[1],
height_upper = boxplot(height, plot=FALSE)$stats[5],
diam_lower = boxplot(stemDiameter, plot=FALSE)$stats[1],
diam_upper = boxplot(stemDiameter, plot=FALSE)$stats[5]) %>%
filter(height > height_lower & height < height_upper,
stemDiameter > diam_lower & stemDiameter < diam_upper) %>%
dplyr::select(-height_lower, -height_upper, -diam_lower, -diam_upper) %>%
ungroup()
# Select columns
veg = veg %>%
dplyr::select(siteID, stemDiameter, height, plantStatus, scientificName, taxonID, date, individualID)
Get the 20 Most Commmon Species# Find top 20 species by observation count
species = veg %>%
group_by(taxonID, scientificName) %>%
summarize(obs_count = n()) %>%
arrange(desc(obs_count)) %>%
head(20) %>%
select(taxonID, scientificName) %>%
ungroup() %>%
mutate(num = row_number()) %>%
as.data.frame()
Write Output Files for Shiny AppsaveRDS(veg, './veg_data_for_shiny.Rdata')
saveRDS(species, './species.Rdata')
Part 3. The Shiny app
Server Functionserver = function(input, output) {
selection = reactive({
as.numeric(input$optionNum)
})
selected_data <- reactive({
df <- veg %>%
filter(taxonID == species$taxonID[as.numeric(input$optionNum)]) %>%
dplyr::select(individualID, siteID,scientificName, plantStatus, date, stemDiameter, height)
if(!input$Live){
df = df %>% filter(plantStatus != "Live")
}
if(!input$Live_DD){
df = df %>% filter(plantStatus != "Live, disease damaged")
}
if(!input$Live_PD){
df = df %>% filter(plantStatus != "Live, physically damaged")
}
if(!input$Live_BB){
df = df %>% filter(plantStatus != "Live, broken bole")
}
if(!input$Live_ID){
df = df %>% filter(plantStatus != "Live, insect damaged")
}
if(!input$Live_OD){
df = df %>% filter(plantStatus != "Live, other damage")
}
print(df)
df
})
output$table <- DT::renderDataTable({
table <- selected_data()
})
output$plot1 <- renderPlot({
ggplot(data = selected_data(),
aes(x = stemDiameter, y = height)) +
theme_bw() +
geom_point(aes(color = siteID), alpha = 0.4) +
geom_smooth(color = "black",size = 0.5, se = F) +
xlab("Stem Diameter [cm]") +
ylab("Tree Height [m]") +
# ggtitle(paste("Selected Species:",
# species$scientificName[selection()])) +
labs(colour = "NEON Site ID")+
theme(legend.position = "right",
axis.title = element_text(size = 16))
})
output$result <- renderText({
paste("You have selected ", species$scientificName[selection()])
})
}
User Interface Functionui = fluidPage(
theme = shinytheme("readable"),
h3("NEON Woody Plant Vegetation Structure Data"),
p("This app allows for quick visualization of tree height and diameter data for the 20 most common species in the NEON woody vegetation structure dataset. The data have been filtered to remove dead trees and obvious outliers for height and diameter. "),
HTML("<p style='color:#808080'>NEON (National Ecological Observatory Network). Woody plant vegetation structure, RELEASE-2021 (DP1.10098.001). https://doi.org/10.48443/e3qn-xw47. Dataset accessed from https://data.neonscience.org on November 24, 2021 </p>"),
p("\n"),
fluidRow(column(width = 12, selectInput(inputId = "optionNum",
label = "Choose a Species Group",
choices = input_options,
selected = 1))),
fluidRow(column(width = 1, checkboxInput("Live", "Live", TRUE)),
column(width = 2, checkboxInput("Live_DD", "Live, disease damaged", TRUE,)),
column(width = 2, checkboxInput("Live_PD", "Live, physically damaged", TRUE)),
column(width = 2, checkboxInput("Live_BB", "Live, broken bole", TRUE)),
column(width = 2, checkboxInput("Live_ID", "Live, insect damaged", TRUE)),
column(width = 2, checkboxInput("Live_OD", "Live, other damage", TRUE))),
mainPanel(tabsetPanel(type = "tabs",
tabPanel(title ="Plot", plotOutput('plot1')),
tabPanel("Data Table", DT::dataTableOutput('table')))
)
)
App Setup# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
Run the AppshinyApp(ui = ui, server = server)
veg = veg_ind %>%
inner_join(veg_loc, by = c("individualID", "siteID", "plotID")) %>%
inner_join(plot_info, by = c("siteID", "plotID", "eventID"))
veg %>% head()
## siteID plotID height individualID plantStatus
## 1 BART BART_044 5.6 NEON.PLA.D01.BART.05332 Live, disease damaged
## 2 BART BART_037 11.5 NEON.PLA.D01.BART.05273 Live, disease damaged
## 3 BART BART_037 1.8 NEON.PLA.D01.BART.05262 Live, disease damaged
## 4 BART BART_044 0.8 NEON.PLA.D01.BART.05424 Live
## 5 BART BART_044 10.4 NEON.PLA.D01.BART.05415 Live, disease damaged
## 6 BART BART_044 1.1 NEON.PLA.D01.BART.05319 Live
## stemDiameter date eventID domainID taxonID
## 1 5.8 2015-08-26 vst_BART_2015 D01 FAGR
## 2 10.3 2015-08-26 vst_BART_2015 D01 FAGR
## 3 1.6 2015-08-26 vst_BART_2015 D01 FAGR
## 4 1.4 2015-08-26 vst_BART_2015 D01 TSCA
## 5 12.5 2015-08-26 vst_BART_2015 D01 FAGR
## 6 1.2 2015-08-26 vst_BART_2015 D01 PICEA
## scientificName plotType
## 1 Fagus grandifolia Ehrh. tower
## 2 Fagus grandifolia Ehrh. tower
## 3 Fagus grandifolia Ehrh. tower
## 4 Tsuga canadensis (L.) Carrière tower
## 5 Fagus grandifolia Ehrh. tower
## 6 Picea sp. tower
veg = veg %>%
# filter for Live trees
filter(substr(plantStatus, 1,4) == "Live") %>%
# filter for tree measurements (which start at 10cm)
filter(stemDiameter > 10) %>%
filter(is.na(height) == F & is.na(stemDiameter) == F) %>%
# remove outliers
group_by(taxonID) %>%
mutate(height_lower = boxplot(height, plot=FALSE)$stats[1],
height_upper = boxplot(height, plot=FALSE)$stats[5],
diam_lower = boxplot(stemDiameter, plot=FALSE)$stats[1],
diam_upper = boxplot(stemDiameter, plot=FALSE)$stats[5]) %>%
filter(height > height_lower & height < height_upper,
stemDiameter > diam_lower & stemDiameter < diam_upper) %>%
dplyr::select(-height_lower, -height_upper, -diam_lower, -diam_upper) %>%
ungroup()
# Select columns
veg = veg %>%
dplyr::select(siteID, stemDiameter, height, plantStatus, scientificName, taxonID, date, individualID)
Get the 20 Most Commmon Species# Find top 20 species by observation count
species = veg %>%
group_by(taxonID, scientificName) %>%
summarize(obs_count = n()) %>%
arrange(desc(obs_count)) %>%
head(20) %>%
select(taxonID, scientificName) %>%
ungroup() %>%
mutate(num = row_number()) %>%
as.data.frame()
Write Output Files for Shiny AppsaveRDS(veg, './veg_data_for_shiny.Rdata')
saveRDS(species, './species.Rdata')
Part 3. The Shiny app
Server Functionserver = function(input, output) {
selection = reactive({
as.numeric(input$optionNum)
})
selected_data <- reactive({
df <- veg %>%
filter(taxonID == species$taxonID[as.numeric(input$optionNum)]) %>%
dplyr::select(individualID, siteID,scientificName, plantStatus, date, stemDiameter, height)
if(!input$Live){
df = df %>% filter(plantStatus != "Live")
}
if(!input$Live_DD){
df = df %>% filter(plantStatus != "Live, disease damaged")
}
if(!input$Live_PD){
df = df %>% filter(plantStatus != "Live, physically damaged")
}
if(!input$Live_BB){
df = df %>% filter(plantStatus != "Live, broken bole")
}
if(!input$Live_ID){
df = df %>% filter(plantStatus != "Live, insect damaged")
}
if(!input$Live_OD){
df = df %>% filter(plantStatus != "Live, other damage")
}
print(df)
df
})
output$table <- DT::renderDataTable({
table <- selected_data()
})
output$plot1 <- renderPlot({
ggplot(data = selected_data(),
aes(x = stemDiameter, y = height)) +
theme_bw() +
geom_point(aes(color = siteID), alpha = 0.4) +
geom_smooth(color = "black",size = 0.5, se = F) +
xlab("Stem Diameter [cm]") +
ylab("Tree Height [m]") +
# ggtitle(paste("Selected Species:",
# species$scientificName[selection()])) +
labs(colour = "NEON Site ID")+
theme(legend.position = "right",
axis.title = element_text(size = 16))
})
output$result <- renderText({
paste("You have selected ", species$scientificName[selection()])
})
}
User Interface Functionui = fluidPage(
theme = shinytheme("readable"),
h3("NEON Woody Plant Vegetation Structure Data"),
p("This app allows for quick visualization of tree height and diameter data for the 20 most common species in the NEON woody vegetation structure dataset. The data have been filtered to remove dead trees and obvious outliers for height and diameter. "),
HTML("<p style='color:#808080'>NEON (National Ecological Observatory Network). Woody plant vegetation structure, RELEASE-2021 (DP1.10098.001). https://doi.org/10.48443/e3qn-xw47. Dataset accessed from https://data.neonscience.org on November 24, 2021 </p>"),
p("\n"),
fluidRow(column(width = 12, selectInput(inputId = "optionNum",
label = "Choose a Species Group",
choices = input_options,
selected = 1))),
fluidRow(column(width = 1, checkboxInput("Live", "Live", TRUE)),
column(width = 2, checkboxInput("Live_DD", "Live, disease damaged", TRUE,)),
column(width = 2, checkboxInput("Live_PD", "Live, physically damaged", TRUE)),
column(width = 2, checkboxInput("Live_BB", "Live, broken bole", TRUE)),
column(width = 2, checkboxInput("Live_ID", "Live, insect damaged", TRUE)),
column(width = 2, checkboxInput("Live_OD", "Live, other damage", TRUE))),
mainPanel(tabsetPanel(type = "tabs",
tabPanel(title ="Plot", plotOutput('plot1')),
tabPanel("Data Table", DT::dataTableOutput('table')))
)
)
App Setup# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
Run the AppshinyApp(ui = ui, server = server)
# Find top 20 species by observation count
species = veg %>%
group_by(taxonID, scientificName) %>%
summarize(obs_count = n()) %>%
arrange(desc(obs_count)) %>%
head(20) %>%
select(taxonID, scientificName) %>%
ungroup() %>%
mutate(num = row_number()) %>%
as.data.frame()
saveRDS(veg, './veg_data_for_shiny.Rdata')
saveRDS(species, './species.Rdata')
Part 3. The Shiny app
Server Functionserver = function(input, output) {
selection = reactive({
as.numeric(input$optionNum)
})
selected_data <- reactive({
df <- veg %>%
filter(taxonID == species$taxonID[as.numeric(input$optionNum)]) %>%
dplyr::select(individualID, siteID,scientificName, plantStatus, date, stemDiameter, height)
if(!input$Live){
df = df %>% filter(plantStatus != "Live")
}
if(!input$Live_DD){
df = df %>% filter(plantStatus != "Live, disease damaged")
}
if(!input$Live_PD){
df = df %>% filter(plantStatus != "Live, physically damaged")
}
if(!input$Live_BB){
df = df %>% filter(plantStatus != "Live, broken bole")
}
if(!input$Live_ID){
df = df %>% filter(plantStatus != "Live, insect damaged")
}
if(!input$Live_OD){
df = df %>% filter(plantStatus != "Live, other damage")
}
print(df)
df
})
output$table <- DT::renderDataTable({
table <- selected_data()
})
output$plot1 <- renderPlot({
ggplot(data = selected_data(),
aes(x = stemDiameter, y = height)) +
theme_bw() +
geom_point(aes(color = siteID), alpha = 0.4) +
geom_smooth(color = "black",size = 0.5, se = F) +
xlab("Stem Diameter [cm]") +
ylab("Tree Height [m]") +
# ggtitle(paste("Selected Species:",
# species$scientificName[selection()])) +
labs(colour = "NEON Site ID")+
theme(legend.position = "right",
axis.title = element_text(size = 16))
})
output$result <- renderText({
paste("You have selected ", species$scientificName[selection()])
})
}
User Interface Functionui = fluidPage(
theme = shinytheme("readable"),
h3("NEON Woody Plant Vegetation Structure Data"),
p("This app allows for quick visualization of tree height and diameter data for the 20 most common species in the NEON woody vegetation structure dataset. The data have been filtered to remove dead trees and obvious outliers for height and diameter. "),
HTML("<p style='color:#808080'>NEON (National Ecological Observatory Network). Woody plant vegetation structure, RELEASE-2021 (DP1.10098.001). https://doi.org/10.48443/e3qn-xw47. Dataset accessed from https://data.neonscience.org on November 24, 2021 </p>"),
p("\n"),
fluidRow(column(width = 12, selectInput(inputId = "optionNum",
label = "Choose a Species Group",
choices = input_options,
selected = 1))),
fluidRow(column(width = 1, checkboxInput("Live", "Live", TRUE)),
column(width = 2, checkboxInput("Live_DD", "Live, disease damaged", TRUE,)),
column(width = 2, checkboxInput("Live_PD", "Live, physically damaged", TRUE)),
column(width = 2, checkboxInput("Live_BB", "Live, broken bole", TRUE)),
column(width = 2, checkboxInput("Live_ID", "Live, insect damaged", TRUE)),
column(width = 2, checkboxInput("Live_OD", "Live, other damage", TRUE))),
mainPanel(tabsetPanel(type = "tabs",
tabPanel(title ="Plot", plotOutput('plot1')),
tabPanel("Data Table", DT::dataTableOutput('table')))
)
)
App Setup# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
Run the AppshinyApp(ui = ui, server = server)
server = function(input, output) {
selection = reactive({
as.numeric(input$optionNum)
})
selected_data <- reactive({
df <- veg %>%
filter(taxonID == species$taxonID[as.numeric(input$optionNum)]) %>%
dplyr::select(individualID, siteID,scientificName, plantStatus, date, stemDiameter, height)
if(!input$Live){
df = df %>% filter(plantStatus != "Live")
}
if(!input$Live_DD){
df = df %>% filter(plantStatus != "Live, disease damaged")
}
if(!input$Live_PD){
df = df %>% filter(plantStatus != "Live, physically damaged")
}
if(!input$Live_BB){
df = df %>% filter(plantStatus != "Live, broken bole")
}
if(!input$Live_ID){
df = df %>% filter(plantStatus != "Live, insect damaged")
}
if(!input$Live_OD){
df = df %>% filter(plantStatus != "Live, other damage")
}
print(df)
df
})
output$table <- DT::renderDataTable({
table <- selected_data()
})
output$plot1 <- renderPlot({
ggplot(data = selected_data(),
aes(x = stemDiameter, y = height)) +
theme_bw() +
geom_point(aes(color = siteID), alpha = 0.4) +
geom_smooth(color = "black",size = 0.5, se = F) +
xlab("Stem Diameter [cm]") +
ylab("Tree Height [m]") +
# ggtitle(paste("Selected Species:",
# species$scientificName[selection()])) +
labs(colour = "NEON Site ID")+
theme(legend.position = "right",
axis.title = element_text(size = 16))
})
output$result <- renderText({
paste("You have selected ", species$scientificName[selection()])
})
}
ui = fluidPage(
theme = shinytheme("readable"),
h3("NEON Woody Plant Vegetation Structure Data"),
p("This app allows for quick visualization of tree height and diameter data for the 20 most common species in the NEON woody vegetation structure dataset. The data have been filtered to remove dead trees and obvious outliers for height and diameter. "),
HTML("<p style='color:#808080'>NEON (National Ecological Observatory Network). Woody plant vegetation structure, RELEASE-2021 (DP1.10098.001). https://doi.org/10.48443/e3qn-xw47. Dataset accessed from https://data.neonscience.org on November 24, 2021 </p>"),
p("\n"),
fluidRow(column(width = 12, selectInput(inputId = "optionNum",
label = "Choose a Species Group",
choices = input_options,
selected = 1))),
fluidRow(column(width = 1, checkboxInput("Live", "Live", TRUE)),
column(width = 2, checkboxInput("Live_DD", "Live, disease damaged", TRUE,)),
column(width = 2, checkboxInput("Live_PD", "Live, physically damaged", TRUE)),
column(width = 2, checkboxInput("Live_BB", "Live, broken bole", TRUE)),
column(width = 2, checkboxInput("Live_ID", "Live, insect damaged", TRUE)),
column(width = 2, checkboxInput("Live_OD", "Live, other damage", TRUE))),
mainPanel(tabsetPanel(type = "tabs",
tabPanel(title ="Plot", plotOutput('plot1')),
tabPanel("Data Table", DT::dataTableOutput('table')))
)
)
App Setup# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
Run the AppshinyApp(ui = ui, server = server)
# load saved datasets
veg = readRDS('./veg_data_for_shiny.Rdata')
species = readRDS('./species.Rdata')
# format input options
input_options = species$num
names(input_options) = species$scientificName
shinyApp(ui = ui, server = server)