SelectInput and dateRangeinput functions - r

I really need your help. I am new in R shiny and I have to use 2 reactives functions. I have a table of a DataBase which columns (id_cli, val_cli, date_cli) example (1, 12, 2020-02-01); (1,30,2020-02-02); (2, 80,2020-02-03), etc the id_cli is foreign key, so it isnt unique in this table. I want to select the id_cli using the function selectInput and from there select a date range using the dateRangeInput function
This is my code :
DB <- dbConnect(MySQL(),
user='xx',
host='xxx.xxx.x.xx')
req22 = dbGetQuery(DB, "select id_cli, val_cli, date_cli from t_client;")
agg22 = setNames(aggregate(req22[,1:2], list(req22$date_cli), mean), c("date_cli", "id_cli","val_cli"))
agg22$date_cli = as.Date(agg22$date_cli)
dates22 <- seq(from = min(agg22$date_cli),
to = max(agg22$date_cli),
by="days")
tweets22 <- data.frame(dateW = dates22, agg22$val_cli, agg22$id_cli)
selectInput(inputId = "id_cli2", label = h3("List of clients"), choices = tweets22$agg22.id_cli)
dateRangeInput(inputId="dateW", label ="Selectionne a Date",
start = min(tweets22$agg22.date_cli),
end = max(tweets22$agg22.date_cli),
min = min(tweets22$agg22.date_cli),
max= max(tweets22$agg22.date_cli))
query <- reactive({
tweets22 %>%
select(agg22.id_cli, dateW, agg22.val_cli) %>%
filter(agg22.id_cli == input$id_cli2)
})
newtweets22 <-reactive({
query()
filter(tweets22, between(dateW, input$dateW[1], input$dateW[2]))
})
renderPlot({
ggplot(newtweets22(), aes(x=dateW, y=agg22.val_cli))+ geom_line(size=1) + xlab ("Date") + ylab("Values")
})
The code takes all the date range of data but does not select by id_cli which is input$cli Someone can help me please ?

Edit: I added filter(id_cli == input$id_cli2) to respond to your update.
Do you want something like this?
library(tidyverse)
library(lubridate)
library(shiny)
ui <- fluidPage(
uiOutput("select_ui"),
uiOutput("date_ui"),
plotOutput("plot")
)
server <- function(input, output, session){
req22 <- reactive({
# Replace this with your database query:
tibble(id_cli = c(1,1,1,2,2,2),
val_cli = c(12,30,80,70,50,20),
date_cli = c(ymd("2020-02-01"), ymd("2020-02-02"), ymd("2020-02-03"),
ymd("2020-02-04"), ymd("2020-02-05"), ymd("2020-02-06")))
})
output$select_ui <- renderUI({
req(req22())
clients <- req22() %>% distinct(id_cli) %>% pull %>% sort
selectInput("id_cli2", "List of clients", choices = clients)
})
output$date_ui <- renderUI({
req(req22())
dates <- req22() %>%
filter(id_cli == input$id_cli2) %>%
summarize(mindate = min(date_cli),
maxdate = max(date_cli))
dateRangeInput("dateW", "Select a date",
start = dates$mindate,
min = dates$mindate,
max = dates$maxdate,
end = dates$maxdate)
})
output$plot <- renderPlot({
req(req22(), input$dateW, input$id_cli2)
req22() %>%
filter(date_cli >= input$dateW[[1]],
date_cli <= input$dateW[[2]],
id_cli == input$id_cli2) %>%
ggplot(aes(x=date_cli, y = val_cli)) +
geom_point() +
geom_line()
})
}
shinyApp(ui = ui, server = server)
I assume that each time the user changes the client ID, you want the dates to default to the widest range relevant to that client. If you want to remember the user's previous date selections, then you should store them in a reactiveVal using observeEvent and then also use this in the filtering.

Thanks a lot for your answer. Yes I want like this but there is something doesnt Ok.
If I consider your code with this new data :
req22 <- reactive({
# Replace this with your database query:
tibble(id_cli = c(1,1,1,2,2,2),
val_cli = c(12,30,80,70,50,20),
date_cli = c(ymd("2020-02-01"), ymd("2020-02-02"), ymd("2020-02-03"),
c(ymd("2020-02-04"), c(ymd("2020-02-05"), c(ymd("2020-02-06")))
})
In the user interface when I select 1 of List of cients, in the select date range I want to have automaticaly 2020-02-01 to 2020-02-03 and when I select 2 of List of clients I want to see in the Select a date automatcaly the date between 2020-02-04 to 2020-02-06
The plot is OK, but there is the prolem only in the DateRangeInput.
Thanks in advance for your help :)

Related

Select a variable based on two inputs in Rshiny

I have a dataset with variables for the ID of patients, different tests (MMT), and the treatment.
ID
MMT_II_week15_change
MMT_II_Week20_change
MMT_Tot_week15_change
MMT_Tot_Week20_change
Treatment
As you can see, we have two different tests (MMT_II_change and MMT_Tot_change), for two different timepoints (week15, week20).
What I want is the user to be able to select, first, the test, and then, the timepoint.
In reality, he would be picking just one of the variables, but in two different steps.
Something like:
**Select test:**
MMT_II
MMT_III
**Select timepoint:**
Week15
Week20
And after this, the variable selected would be:
e.g: MMT_II_Week20_change
I though of using regex for this, but it seems quite complicated and coulnd't find of a way of doing it.
Any help really appreciated, as I've been stuck with this for a while.
Would something like this work?
VAR = paste0(test,"_",timepoint,"_change")
...
# then later to use the variable...
.data[[VAR]]
You can wrap the checking of changess occured in a single reactive function in the server section of your code.
uptodateChoice <- reactive({
paste0(input$firstcontrol, "_", input$secondcontrol, "_change")
})
This function will be called once any of the two controls state change.
You can also add any validate(need(...)) checks inside the function if required or simply return() if some conditions are not satisfied.
You can access the string value calling uptodateChoice().
I'm thinking about pivoting the data to longer format, filter it and then pivot again to wider. This way we can filter using filter function directly.
library(tidyverse)
library(shiny)
# create some data
df <- tibble(
ID = 1:5, MMT_II_week15_change = sample(seq(0.01, 0.2, 0.01), 5), MMT_II_week20_change = sample(seq(0.01, 0.2, 0.01), 5),
MMT_Tot_week15_change = sample(seq(0.01, 0.2, 0.01), 5), MMT_Tot_week20_change = sample(seq(0.01, 0.2, 0.01), 5)
)
# pivot wider capturing MMT_* for the first column and the number of week in the second.
df_pivot <- pivot_longer(df, -ID, names_to = c("test", "week"), values_to = "change", names_pattern = "(MMT_.*)_week(\\d+)_change$")
## APP
library(shiny)
ui <- fluidPage(
selectInput("test", "Select Test", choices = unique(df_pivot$test)),
selectInput("timepoint", "Select Timepoint", choices = NULL),
tableOutput("table")
)
server <- function(input, output, session) {
table <- reactiveVal(NULL)
observeEvent(input$test, {
choices <- filter(.data = df_pivot, test == input$test) %>%
{
unique(.$week)
}
updateSelectInput(inputId = "timepoint", choices = choices)
})
# this could also be a reactive.
observe({
table(filter(df_pivot, test == input$test, week == input$timepoint) %>%
pivot_wider(names_from = "test", values_from = "change"))
})
output$table <- renderTable({
table()
})
}
shinyApp(ui, server)

R shiny error when using reactive to plot

I have this data set:
Area <- c("Mexico", "USA", "USA", "Canada").
Type_of_participants <- c("Doctor", "Doctor", "Engineer", "Dancer".
Salary <- c("4000", "6000", "8000", "5000").
and I am trying to plot the salary base on the user input of Area(level1) and Type_of_participants(level2), but nothing appears. I modified aes to aes_string as I looked up here. Please help me find the error
My Code
`ui <- fluidPage(
titlePanel("Survey Results"),
sidebarLayout(
sidebarPanel(strong("Overview Plot"),
br(),
###1a.Area input
selectInput("selection","Var",
choices = c("Area","Type_of_participants"),
selected = "Area"),
uiOutput("choice_selection")
),
mainPanel(
plotOutput("Overview"))
`server <- function(input, output) {
output$choice_selection <- renderUI({
checkboxGroupInput("baseinput","Detail",
unique(df[,input$selection])
)`
})
dt1 <- reactive({
df %>%
group_by(input$selection,Type) %>%
filter (input$selection %in% input$baseinput) %>%
summarise(avg_salary_by_area = mean(Salary, na.rm = TRUE)) %>%
select(input$selection, Type, avg_Salary_by_area)
})
output$Overview <- renderPlot({
ggplot(data= dt1())+
aes(fill = Type)+
geom_bar(x=input$selection, y = avg_salary_by_area,stat="identity",
position = position_dodge())
The result is I can select the input but can not visualize the plot. The error "unknown column Area or unknow Type of participants
Please help me find the mistake
Thank you
*** Update
Thanks to Mr Flick, I have fixed my code but it still informs error "Object area not found". Please help to advise. Thank you so much
`dt1 <- reactive({
df[df[,input$selection] %in% input$baseinput,] %>%
group_by(input$selection,Type) %>%
summarise(avg_score_by_area = mean(Score, na.rm = TRUE))
})
output$Overview <- renderPlot({
ggplot(data= dt1(),aes_string(x= input$selection,
y = "avg_score_by_area",fill = "Type"))+
geom_bar(stat="identity",
position = position_dodge())`
#Suzie - as mentioned above, it would help if you edited your question with your complete code as you currently have it.
A few things that would help:
Salary should be numeric in your df (or be converted with as.numeric before trying to take the mean
Your reactive expression can use !!as.symbol with input$selection to filter by the string name from df
The plot can use aes_string for the variable names.
Edit:
For further explanation of !!as.symbol, first consider what the result of input$selection. If you use browser() in your shiny code, and inspect what input$selection returns, you will see something like "Area" (it returns a string). But a string would not be appropriate in your filter - it is expecting a symbol that represents a column in your data frame. (A symbol is the name of an object like df or mtcars, etc.)
First, you want to convert a string to a symbol. You can do that either by using as.symbol() or rlang::sym(). You can try this out in your console. If you do as.symbol("df") it would return the symbol df. If you entered eval(as.symbol("df")) it would be the same as just entering df itself (and it would show the contents of your data frame).
The other issue is that tidyverse functions evaluate code expressions in a special context (searching for names within a data frame, for example). In this case dplyr knows that the name Area is in the context of df (one of the column names). This is a complicating factor since arguments are quoted. To address this, you need to unquote (replace a name with its value) with the bang-bang !! operator.
Putting both together you get !!as.symbol().
Of note, varSelectInput is a newer shiny alternative to selectInput that can be considered for use in situations like these.
For more information:
shinymeta special topics
advanced R
library(tidyverse)
library(shiny)
Area <- c("Mexico", "USA", "USA", "Canada")
Type_of_participants <- c("Doctor", "Doctor", "Engineer", "Dancer")
Salary <- c(4000, 6000, 8000, 5000)
df <- data.frame(Area, Type_of_participants, Salary)
ui <- fluidPage(
titlePanel("Survey Results"),
sidebarLayout(
sidebarPanel(strong("Overview Plot"),
br(),
###1a.Area input
selectInput("selection","Var",
choices = c("Area","Type_of_participants"),
selected = "Area"),
uiOutput("choice_selection")
),
mainPanel(
plotOutput("Overview")
)
)
)
server <- function(input, output) {
output$choice_selection <- renderUI({
checkboxGroupInput("baseinput", "Detail", unique(df[,input$selection]))
})
dt1 <- reactive({
df %>%
group_by(Area, Type_of_participants) %>%
filter(!!as.symbol(input$selection) %in% input$baseinput) %>%
summarise(avg_salary_by_area = mean(Salary, na.rm = TRUE))
})
output$Overview <- renderPlot({
ggplot(data = dt1(), aes_string(x = input$selection, y = "avg_salary_by_area", fill = "Type_of_participants")) +
geom_bar(stat="identity", position = position_dodge())
})
}
shinyApp(ui, server)

Shiny error : data not being read when connected with a database

An overview of the project: To connect with a postgres DB that contains id,scores and date, so that a shiny dashboard user can enter the id and next I want to compute an upper and lower ranges for the mean(scores) for that id, so that finally I can display all that in a graph.
Issue: Looks like no data is being read from the DB, error: scores not found
Below is the script:
library(ALL relevant libraries)
drv <- dbDriver("PostgreSQL")
con<-dbConnect(drv,dbname = "", host = "", port = "", user = "", password= "")
# correct credentials placed above
dates <- seq(as.Date(as.character(Sys.Date() - 10)), as.Date(as.character(Sys.Date() - 5)), by = 1)
# dates vector should have 5 days
r <<- length(dates)
ui <- fluidPage(
titlePanel("Score"),
sidebarPanel(numericInput(inputId = "id",label = "user", value = 0000 ,
min = 100, max = 1000000)),
mainPanel(plotOutput("Coolplot"))
)
server <- function(input, output, session) {
browser()
generate <- function(r) {
listofdfs <- list() # Create a list in which you intend to save your df's.
for (i in 1:length(dates)) {
data <- dbGetQuery(con, sprintf("select score, CAST (date AS date), id from My_Table
where id = ",input$id," and
date<=date('%s') and date>=date('%s')- INTERVAL '7 day'",dates[i],dates[i]))
# changed the date<='%s' to date<=date('%s') now at least can read the data.
data$score_mean <- mean(data[,1])
data$upper_threshold <- data$score_mean * 1.2
data$lower_threshold <- data$score_mean * 0.8
listofdfs[[i]] <- data # save your dataframes into the list
}
return(listofdfs) #Return the list of dataframes.
}
df <- as.data.frame(do.call("rbind", generate(r)))
df<-reactive({df[!duplicated(df$date)]}) #since data needed some subsetting
output$Coolplot <- renderPlot({
browser()
ggplot(df(), aes(date)) +
geom_line(aes(y = score, colour = "score"))+
geom_line(aes(y = upper_threshold, colour = "upper_threshold")) +
geom_line(aes(y = lower_threshold, colour = "lower_threshold"))
})
}
shinyApp(ui = ui, server = server)
Thank you all for your help.
Cheers!
I don't think you should set an initial value under the min
sidebarPanel(numericInput(inputId = "id",label = "user", value = 0000 , min = 100, max = 1000000)),
=>
sidebarPanel(numericInput(inputId = "id",label = "user", value = 100 , min = 100, max = 1000000)),
Keep generate as a regular function returning something based on provided parameters
generate <- function(r) {
=>
generate <- function(user_id) {
don't mix up sprintf with paste and prevent SQL injection
sprintf("select score, CAST (date AS date), id from My_Table where id = ",input$id," and date<=date('%s') and date>=date('%s')- INTERVAL '7 day'",dates[i],dates[i]))
=>
sprintf("select score, CAST (date AS date), id from My_Table where id = %d and date<=date('%s') and date>=(date('%s')- INTERVAL '7 day')", as.numeric(user_id), as.date(dates[i]), as.date(dates[i])))
Add all your data manipuation within the reactive that references input parameters
df <- as.data.frame(do.call("rbind", generate(r)))
df<-reactive({df[!duplicated(df$date)]})
=>
df<-reactive({
data <- as.data.frame(do.call("rbind", generate(input$id)))
data[!duplicated(data$date)]
})

Shiny - Web Framework for R › how to use an input switch to conditionally group

asked this on the shiny google group, w no help yet: I'm struggling with how to pass an input switch to dplyr's group_by_ in the code below.
I bolded the two parts of relevant code in the not-so-MRE below (ie, lines 9:11, and 24).
effectively, if the user selects "daily" in the UI, the resultant grouping should be group_by(year = year(my_date), month = month(my_date), day = day(my_date) in line 24, or remove ANY grouping as the data is already daily.
selecting "monthly", should yield group_by(year = year(my_date), month = month(my_date))
"yearly", should yield group_by(year = year(my_date))
I welcome meta-suggestions/ criticism about how my code/ structures are organized.
Thank you
library(shiny)
library(dplyr)
library(lubridate)
ui <- fluidPage(
dateInput("start", label = "start date", value = "2010-01-01"),
dateInput("end", label = "end date", value = "2020-01-01"),
selectInput("grouping_freq", label = "Granularity",
choices = list("daily" = 1,"monthly" = 2, "Yearly" = 3),
selected = 2),
tableOutput("my_table")
)
server <- function(input, output) {
df <- reactive({ data_frame(my_date = seq(input$start, input$end, by = 'day')) }) ## 10 years of daily data
df2 <- reactive({ df() %>% mutate(dummy_data = cumsum(rnorm( nrow( df() ) ))) })
output$my_table <- renderTable({
df2() %>% group_by(year = year(my_date), month = month(my_date)) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
}
shinyApp(ui = ui, server = server)
You can use the value chosen in selectInput to create a list of formulas that are passed into group_by_, the version of dplyr::group_by that uses standard evaluation.
group_list <- switch(input$grouping_freq,
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date)),
list(yr=~year(my_date), mn=~month(my_date))
list(yr=~year(my_date)))
or if you prefer if statements,
group_list <- if (input$grouping_freq == 1) {
list(yr=~year(my_date), mn=~month(my_date), dy=~day(my_date))
} else if (input$grouping_freq == 2) {
list(yr=~year(my_date), mn=~month(my_date))
} else if (input$grouping_freq == 3) {
list(yr=~year(my_date))
} else {
list()
}
and then you can pass group_list into the renderTable expression
output$my_table <- renderTable({
df2() %>%
group_by_(.dots=group_list) %>%
summarise(dummy_data = sum(dummy_data), my_date = as.Date(min(my_date)))
})
I am not sure what you meant by "remove ANY grouping as the data is already daily." but if the data might already be grouped you can use the ungroup function to remove any groups before applying the groupings in group_list.
Edit: Forgot to include ~ in the list elements so that they evaluate correctly.

Error with dates and reactive inputs in R Shiny

I am putting together a small R Shiny app which will take several inputs from the user and use these inputs to subset a data frame and provide back two histograms. The users will pick a baseball season, two teams and then this information will provide a reactive list of possible games played between these two teams. The user will then pick a date/game and then a histogram will be displayed for each team which will show the distribution of runs scored per game for each team for all games within that season up to the date/game selected. I feel like I am almost there, I just need to get this date thing sorted out. Right now with the code as is, everything evaluates but I get this error twice;
Warning: Error in eval: do not know how to convert 'input$dates' to class “Date”
and this error twice;
Warning in eval(substitute(expr), envir, enclos) :
Incompatible methods ("Ops.factor", "Ops.Date") for "<"
ui.R
library(shiny)
library(dplyr)
shinyUI(fluidPage(
# Application title
titlePanel("Predicting the winner of a Major League Baseball game"),
sidebarLayout(
sidebarPanel(
selectInput("season","1. Select an MLB Season",
choices = list(2012,2013,2014,2015),
selected = 2012),
selectInput("var_1","2. Select the first team",
choices = c("ARI","ATL","BAL","BOS","CHC","CHW","CIN","CLE","COL","DET",
"HOU","KCR","LAA","LAD","MIA","MIL","MIN","NYM","NYY","OAK",
"PHI","PIT","SDP","SFG","SEA","STL","TBR","TEX","TOR","WSN"),
selected = "BAL"),
selectInput("var_2","3. Select the second team",
choices = c("ARI","ATL","BAL","BOS","CHC","CHW","CIN","CLE","COL","DET",
"HOU","KCR","LAA","LAD","MIA","MIL","MIN","NYM","NYY","OAK",
"PHI","PIT","SDP","SFG","SEA","STL","TBR","TEX","TOR","WSN"),
selected = "BOS"),
uiOutput("dates"),
sliderInput("bins",
"Binwidth:",
min = 1,
max = 5,
value = 2)
),
#main panel
mainPanel(
plotOutput("first_team_hist"),
plotOutput("second_team_hist")
)
)))
server.R
library(shiny)
library(dplyr)
library(ggplot2)
shinyServer(
function(input, output) {
mydf <- read.csv("batting_game_logs_merged.csv")
inputData_1 <- reactive({
filter(mydf,team == input$var_1 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
inputData_2 <- reactive({
filter(mydf,team == input$var_2 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
output$dates <- renderUI({
dates = mydf %>% filter(team == input$var_1 & opponent_team == input$var_2 & season == input$season) %>% select(date)
selectInput("dates","Pick a Game Date", as.character(dates[[1]]))
})
output$first_team_hist <- renderPlot({
myplot_1 <- ggplot(inputData_1(), aes(x = team_batting_gamelogs.R)) +
geom_histogram(aes(y = ..density..),
binwidth = input$bins, fill = I("blue"),col = I("red")) +
labs(title = paste("Runs Scored per game for",input$var_1),
x= "Runs Scored per Game", y = "Density")
print(myplot_1)
})
output$second_team_hist<- renderPlot({
myplot_2 <- ggplot(inputData_2(), aes(x = team_batting_gamelogs.R)) +
geom_histogram(aes(y = ..density..),
binwidth = input$bins, fill = I("blue"),col = I("red")) +
labs(title = paste("Runs Scored per game for",input$var_2),
x= "Runs Scored per Game", y = "Density")
print(myplot_2)
})
}
)
Thank you in advance for taking the time to review my problem.
-Josh
I am guessing your problem is the initial NULL value of your input$dates. Your reactive environments inputData_1/2 respond as soon as your UI is rendered (and they get their selected value). But no value has been assigned to input$dates yet, so your first run of these functions gets a NULL. Confirm that as.Date(NULL) yields exactly your error.
I advice you to make your reactive environments only listen to input$dates, i.e.
inputData_1 <- eventReactive(input$dates, {
filter(mydf,team == input$var_1 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
inputData_2 <- eventReactive(input$dates, {
filter(mydf,team == input$var_2 & season == input$season & date < as.Date(input$dates,format = "%Y-%m-%d"))
})
As far as I can see, you want computations to start only after inserting a date anyway.
Other possible fixes are to isolate the other variables or just add an if(!is.null(input$dates)){ ... } clause to handle NULL input.

Resources