1+ library(shiny )
2+ library(traits )
3+ library(ggplot2 )
4+ library(lubridate )
5+ library(DataCache )
6+ library(timevis )
7+
8+ # set options for BETYdb API
9+ knitr :: opts_chunk $ set(echo = FALSE , cache = TRUE )
10+ options(betydb_key = readLines(' ~/.betykey' , warn = FALSE ),
11+ betydb_url = " https://terraref.ncsa.illinois.edu/bety/" ,
12+ betydb_api_version = ' beta' )
13+
14+ # get list of seasons for user to select from
15+ experiments <- as.data.frame(betydb_query(table = ' experiments' ))
16+ seasons <- unique(experiments [c(' start_date' , ' end_date' )])
17+ rownames(seasons ) <- paste0(' [' , seasons $ start_date , ' ]' , ' - ' , ' [' , seasons $ end_date , ' ]' )
18+
19+ # set page UI
20+ ui <- fluidPage(
21+
22+ column(width = 8 , offset = 2 ,
23+ title = " TERRA-REF Experimental Data" ,
24+
25+ h1(' TERRA-REF Experimental Data' ),
26+
27+ # season menu
28+ selectInput(' selectedSeason' , ' Season' , rownames(seasons )),
29+
30+ hr(),
31+
32+ h3(' Trait Data' ),
33+
34+ # variable menu to be rendered when variables for a given season are parsed in server()
35+ uiOutput(' selectVariable' ),
36+
37+ plotOutput(' traitPlot' ),
38+
39+ hr(),
40+ h3(' Managements Data' ),
41+
42+ timevisOutput(' timeline' )
43+ )
44+
45+ )
46+
47+ # load trait data from BETYdb
48+ # function is used only by DataCache library to get and update data
49+ loadTraitData <- function (startDate , endDate ) {
50+
51+ # set progress bar while API is queried
52+ withProgress(message = " Retrieving BETYdb Data" , value = 0 , {
53+
54+ fullTraitData <- data.frame ()
55+
56+ initialDateDiff <- as.numeric(difftime(endDate , startDate , units = " days" ))
57+ currDate <- startDate
58+ # loop through all days in a given season
59+ while (endDate - currDate != 0 ) {
60+ # get trait data for each day
61+ currTraitData <- betydb_query(table = ' traits' , date = paste0(' ~' , currDate ), limit = ' none' )
62+ fullTraitData <- rbind(fullTraitData , currTraitData [c(' date' , ' mean' , ' variable_id' , ' specie_id' )])
63+ currDate <- currDate + days(1 )
64+
65+ # update progress bar
66+ incProgress(1 / initialDateDiff )
67+ }
68+ })
69+
70+ # format data as for usability with DataCache library
71+ retData <- list (fullTraitData )
72+ names(retData ) <- ' fullTraitData'
73+
74+ return (retData )
75+ }
76+
77+ getManagementsData <- function (startDate , endDate ) {
78+
79+ fullMgmtData <- data.frame ()
80+
81+ currDate <- startDate
82+ while (endDate - currDate != 0 ) {
83+ # get management data for each day
84+ currMgmtData <- betydb_query(table = ' managements' , date = paste0(' ~' , currDate ))
85+ fullMgmtData <- rbind(fullMgmtData , currMgmtData [c(' date' , ' mgmttype' )])
86+ currDate <- currDate + days(1 )
87+ }
88+
89+ return (fullMgmtData )
90+ }
91+
92+ # handle all app logic
93+ server <- function (input , output ) {
94+
95+ # set reactive start date and end date variables to change when selected season changes
96+ selectedSeasonRow <- reactive({ seasons [input $ selectedSeason ,] })
97+ seasonStartDate <- reactive({ as.Date(selectedSeasonRow()$ start_date ) })
98+ seasonEndDate <- reactive({ as.Date(selectedSeasonRow()$ end_date ) })
99+
100+ # set unique cache name for date range for usability with DataCache library
101+ cacheName <- reactive({ paste0(' TraitCache_' , seasonStartDate(), ' _' , seasonEndDate()) })
102+
103+ # render menu for selecting variable to view data for
104+ output $ selectVariable <- renderUI({
105+
106+ # get access to 'fullTraitData' from cache
107+ data.cache(cache.name = cacheName(), loadTraitData , startDate = seasonStartDate(), endDate = seasonEndDate(), frequency = ' daily' )
108+
109+ # get unique variable ids from observations in current season
110+ variableIds <- unique(as.numeric(fullTraitData $ variable_id ))
111+
112+ # query API for readable names for variable ids, set names
113+ variableNames <- vector()
114+ for (variableId in variableIds ) {
115+ varName <- betydb_query(table = ' variables' , id = variableId )$ name
116+ varName <- gsub(' _' , ' ' , varName )
117+ variableNames <- c(variableNames , varName )
118+ }
119+ names(variableIds ) <- variableNames
120+
121+ selectInput(' selectedVariable' , ' Variable' , variableIds )
122+ })
123+
124+ # render plot for selected variable
125+ output $ traitPlot <- renderPlot({
126+
127+ # get access to 'fullTraitData' from cache
128+ data.cache(cache.name = cacheName(), loadTraitData , startDate = seasonStartDate(), endDate = seasonEndDate())
129+
130+ # only render plot of a variable is selected
131+ if (! is.null(input $ selectedVariable )) {
132+ # get observations for selected variable
133+ variableIdData <- betydb_query(table = ' variables' , id = input $ selectedVariable )
134+ variableTraitData <- subset(fullTraitData , variable_id == as.numeric(variableIdData $ id ))
135+
136+ # get specie data for title
137+ specieId <- unique(as.numeric(variableTraitData $ specie_id ))
138+ specieData <- betydb_query(table = ' species' , id = specieId )
139+ title <- paste0(' Mean ' , gsub(' _' , ' ' , variableIdData $ name ), ' for ' , specieData $ scientificname )
140+
141+ # generate timeseries of boxplots from mean value
142+ ggplot(variableTraitData , aes(as.Date(date ), mean )) +
143+ geom_boxplot(aes(group = cut_width(as.Date(date ), 1 ))) +
144+ labs(title = title ,
145+ x = " Observation Dates" , y = variableIdData $ units ) +
146+ theme(text = element_text(size = 20 ), axis.text.x = element_text(angle = 45 , hjust = 1 )) +
147+ expand_limits(y = 0 ) + xlim(seasonStartDate(), seasonEndDate())
148+ }
149+ })
150+
151+ # generate timeline visualization for managements data
152+ output $ timeline <- renderTimevis({
153+ mgmtData <- getManagementsData(startDate = seasonStartDate(), endDate = seasonEndDate())
154+ timelineData <- data.frame (
155+ id = 1 : nrow(mgmtData ),
156+ content = paste0(mgmtData $ mgmttype ),
157+ start = as.Date(mgmtData $ date )
158+ )
159+ timevis(timelineData )
160+ })
161+ }
162+
163+ shinyApp(ui = ui , server = server )
0 commit comments