Multiplot on the same graph with checkboxGroupInput in a Shiny App - r

I want to plot on the same graph one or more plots, depending on the boxes checked in my "checkboxGroupInput".
After checking a few topics on SO, I have found that a easy-to-use solution would be to add "add=TRUE" in the second, third...plots.
Here is a simplified copy of my code :
Server.R
function(input, output) {
dataInput <- reactive({
#I use getMyPlotValues with two parameters.
#idFcast is the one which doesn't work.
m_PARAM$idSite <- input$country
m_PARAM$idFcast <- input$model[i]
getMyPlotValues(m_PARAM)
})
output$plot1 <- renderPlot({
## We plot all the models on the same graph.
if(length(input$model) > 0)
{
firstplot<- TRUE
#To put add = TRUE for the second, third... plots
for(i in 1:length(input$model))
{
valueshere <- dataInput()
#We pick up the vectors (ts,obs) with the function
#And plot them.
if(firstplot)
{
plot(valueshere$ts,valueshere$obs)
}
else
{
plot(valueshere$ts,valueshere$obs,add=TRUE)
}
firstplot <- FALSE
}
}
})
}
And now the UI.R simplified :
shinyUI(fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(
column((4),
selectInput("country", label = h3("Pays"),
choices = list("First" = 2,"Second" = 1), selected = 1)
)
fluidRow(
#checkboxGroupInput
column(6,
checkboxGroupInput("model",
choices = list("First" = 1,"Second"=2,"Third"=3),
selected = 1)
)
)
),
mainPanel
(
plotOutput("plot1")
)
)
)
)
I found on this topic (How can I pass data between functions in a Shiny app) that I could try to pass the variable "i" by writing valueshere <- dataInput()$i... Because I have the feeling this is where the error comes from. I try do display input$model and it works, input$model[i] doesn't.
There must be a problem in my code, as I am a beginner in Shiny, but I couldn't fix, even with all the topics about Shiny on SO.
Thanks for your help and have a nice day !

Seems that add argument isn't work. I finished with the solution that consists in creating plots for all your models and only displays them when it's value is selected. So here is:
I have tried to make your example reproduceble so you will observe some changes
UPDATE: Supposing your SQL statement will give you a vector with your model names (models_list) you could generate Shiny objects using lapply (like here)
library(shiny)
# Simulate data
set.seed(189)
df <- data.frame("obs" = 1:30, "ts" = (rnorm(30)+100)
, "country" = rep(c("First", "Second"), 15)
, "models" = rep(c("First", "Second", "Third"), 10),
stringsAsFactors = F)
# Suppose your SQL query returns this kind of output
models_list <- c("First", "Second", "Third")
models_num <- length(models_list)
# Run App
shiny::runApp(list(
ui = fluidPage(
sidebarLayout(
sidebarPanel(
selectInput("country", label = "Countries",
choices = c("First", "Second"), selected = "First"),
checkboxGroupInput("model", label = "Models",
choices = c("First", "Second", "Third"),
selected = "First")
),
mainPanel(
lapply(1:models_num, function(i) {
plotOutput(paste0('plot', i))
})
)
)
),
server = function(input, output) {
dataInput <- reactive({
df_out <- df[(df$country == input$country), ]
return(df_out)
})
lapply(1:models_num, function(i) {
output[[paste0('plot', i)]] <- renderPlot({
if(any(input$model %in% models_list[i])){
valueshere <- dataInput()[df$models == models_list[i],]
plot(valueshere$ts,valueshere$obs)
}
})
})
}
))

Related

Using a dynamic UI to draw a 3d plot in shiny

I have a dataframe:
df1<-data.frame(a=rnorm(100),b=rnorm(100),c=rnorm(100),ID1=c("A","B"),ID2=(c("A","B","C","D")))
I am drawing a 3d plot with plotly by adding add_trace in a loop, like:
library(shiny)
library(plotly)
library(tidyverse)
df1<-data.frame(a=rnorm(100),b=rnorm(100),c=rnorm(100),ID1=c("A","B"),ID2=(c("A","B","C","D")))
test<-unique(df1$ID2)
tempt.col<-c("red","blue","green","yellow")
p<-plot_ly()
for(i in 1:length(test)){
df2<-df1[df1$ID2==test[i],] %>%
select(a,b,c)
p<-add_trace(p=p,
data = df2,
x=~a,y=~b,z=~c,
type="scatter3d",
marker = list(size=5,color=tempt.col[i]),
mode="markers"
)
}
p
It works very well like:
Now I want to achieve this in shiny, I would like to generate colourInput based on the length of the selected ID, the ui:
ui<-fluidPage(
fluidRow(
sidebarPanel(
selectInput("select1","Select the ID",choices = colnames(df1[,4:5]),multiple = FALSE),
actionButton("act1","Go"),
uiOutput("ui1"),
),
mainPanel(
tableOutput("table1"),
plotlyOutput("plot.3d",height = "1000px")
)
)
)
server:
server<-function(input,output){
tempt.group<-reactive({
unique(df1[,input$select1])
})
observeEvent(input$act1,{
tempt.vector<-list()
tempt.col.name<-isolate(
vector(mode = "list",length = 2)
)
for(i in 1:length(tempt.group())){
tempt.vector[[i]]<-colourpicker::colourInput(
inputId = paste0("ColorID",i),
label = tempt.group()[i])
tempt.col.name[[1]][i]<-paste0("ColorID",i)
tempt.col.name[[2]][i]<-tempt.group()[i]
}
output$ui1<-renderUI({
tempt.vector
})
names(tempt.col.name)<-c("inputId","label")
col.name<-reactive({
data.frame(sapply(tempt.col.name,cbind))
})
col.df<-reactive({
tempt.col.df<-reactiveValuesToList(input)
data.frame(
names = names(tempt.col.df[grepl("ColorID", names(tempt.col.df))]),
values = unlist(tempt.col.df[grepl("ColorID", names(tempt.col.df))], use.names = FALSE)
)
})
group.col.df<-reactive({
merge(col.df(),col.name(),by.x="names",by.y="inputId")
})
output$table1<-renderTable(
group.col.df()
)
pp<-reactive({
p<-plot_ly()
for(i in 1:length(tempt.group())){
# col<-group.col.df()[group.col.df()[,"label"]==tempt.group()[i],"values"] ####it should be something wrong with here
df2<-df1[df1$ID==tempt.group()[i],] %>%
select(a,b,c)
p<-add_trace(p=p,
data = df2,
x=~a,y=~b,z=~c,
type="scatter3d",
# marker = list(size=5,color=col[i]), ####it should be something wrong with here
mode="markers"
)
}
p
})
output$plot.3d<-renderPlotly({
pp()
})
})
}
shinyApp(ui=ui,server=server)
The app is like:
I want to fetch the colourInput and pass to the color of the 3d scatter plot, but nothing works. The page either keeps refreshing or frozen,
That must be something wrong with col<-group.col.df()[group.col.df()[,"label"]==tempt.group()[i],"values"] and marker = list(size=5,color=col[i]),
please help.
The below works as intended.
library(shiny)
library(plotly)
df1<-data.frame(a=rnorm(100),b=rnorm(100),c=rnorm(100),ID1=c("A","B"),ID2=(c("A","B","C","D")))
# Define UI
ui<-fluidPage(
fluidRow(
sidebarPanel(
selectInput("select1","Select the ID",choices = colnames(df1[,4:5]),multiple = FALSE),
# actionButton("act1","Go"),
uiOutput("myui"),
# keep track of the last selection on all selectInput created dynamically
),
mainPanel(
#tableOutput("table1"),
plotlyOutput("plot.3d",height = "1000px")
)
)
)
# Define server logic required to draw a histogram
server<-function(input,output){
rv <- reactiveValues(mygroup=0, uitaglist = list(), uilabels = list(), input_subset = list(), plotly=NULL)
observeEvent(input$select1, {
newgroup <- unique(df1[,input$select1])
rv$mygroup <- newgroup
# ui tags
rv$uitaglist <- list()
for(i in 1:length(rv$mygroup)){
rv$uitaglist[[i]]<-colourpicker::colourInput(
inputId = paste0("ColorID",i),
label = rv$mygroup[i])
rv$uilabels[[i]] <- paste0("ColorID",i)
}
})
output$myui <- renderUI({
rv$input_subset <- rv$uitaglist
})
observe({
rv$input_subset <- lapply(rv$uilabels, function(x) input[[x]])
p<-plot_ly()
for(i in 1:length(rv$mygroup)) {
df2<-df1[df1$ID2 == rv$mygroup[i],] %>% select(a,b,c)
p<-add_trace(p=p,
data = df2,
x=~a,y=~b,z=~c,
type="scatter3d",
marker = list(size=5,color=rv$input_subset[[i]]),
mode="markers"
)
}
rv$plotly <- p
})
output$plot.3d<-renderPlotly({
rv$plotly
})
} # end server
# Run the application
shinyApp(ui = ui, server = server)
The main difficulty was to observe all your dynamically-generated UI inputs at once. Turns out it could be done using observe and lapply.
Observing several inputs is problematic because the error Must use single string to index into reactivevalues is returned by trying to index input by a vector or list.
Now, Why this can't be done out-of-the-box is a good question.

Using Shiny and checkboxGroupInput to update a table via bind_rows or rbind and using if else statements

I have three tables (math, science, and literature results). I would like to have a "dynamic" table that updates some columns when clicking a checkboxGroupInput option. To do that, I'm using the bind_rows function, but I'm not being able to update the table the way I want.
The final output needs to be something like the gif below:
(1) When I click "math" it shows the math results
(2) when I click "literature" (sorry for the typo), it shows the literature results
etc..
I added
if (input$overall_boxes == "sci") { table_science } else { FALSE } #when I click "sci" is shows the science results (and keep the math if math is selected)
if (input$overall_boxes == "lit") { table_litterature } else { FALSE }
on purpose to demonstrate what is the goal.
If you have another strategy to run that, feel comfortable changing the following code
library(shiny)
library(tidyverse)
table_math <- data.frame(age = c(5,10), test = "math", result = rnorm(100,10,2))
table_science <- data.frame(age = c(10,15), test = "science", result = rnorm(100,8,2))
table_litterature <- data.frame(age = c(5,15), test = "litterature", result = rnorm(100,5,2))
# Define UI for application that draws a histogram
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
checkboxGroupInput("overall_boxes", label = h3("This is a Checkbox group"),
choices = list("Math" = "math", "Sciences" = "sci", "Litterature" = "lit"),
selected = "math")
),
# Show a plot of the generated distribution
mainPanel(
dataTableOutput("main_results")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
#backend
merge_results <- reactive({
bind_rows(
if (input$overall_boxes == "math") { table_math } else { FALSE } #when I click "math" is shows the math results
)
})
#real output
output$main_results <- renderDataTable(
merge_results()
)
}
# Run the application
shinyApp(ui = ui, server = server)
input$overall_boxes may contain multiple elements, so that you should use %in% instead of == in the if statement.
Try:
library(shiny)
library(tidyverse)
table_math <- data.frame(age = c(5,10), test = "math", result = rnorm(100,10,2))
table_science <- data.frame(age = c(10,15), test = "science", result = rnorm(100,8,2))
table_litterature <- data.frame(age = c(5,15), test = "litterature", result = rnorm(100,5,2))
# Define UI for application that draws a histogram
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
checkboxGroupInput("overall_boxes", label = h3("This is a Checkbox group"),
choices = list("Math" = "math", "Sciences" = "sci", "Litterature" = "lit"),
selected = "math")
),
# Show a plot of the generated distribution
mainPanel(
dataTableOutput("main_results")
)
)
)
# Define server logic required to draw a histogram
server <- function(input, output) {
#backend
merge_results <- reactive({
bind_rows(
if ("math" %in% input$overall_boxes) { table_math } else { table_math[F,] }, #when I click "math" is shows the math results
if ("sci" %in% input$overall_boxes) { table_science } else { table_science[F,] } ,#when I click "sci" is shows the science results (and keep the math if math is selected)
if ("lit" %in% input$overall_boxes) { table_litterature } else { table_litterature[F,]}
)
})
#real output
output$main_results <- renderDataTable(
merge_results()
)
}
# Run the application
shinyApp(ui = ui, server = server)

R Shinydashboard filter not working properly with multiple sorts

Below is a code I've been working where the goal is to sort and compare data. However when I try to add multiple factors to compare the data appears to get confused. My expectation is that when I run my app and begin to select multiple PetalWidth options it should show me more data, however the filter doesn't seem to be broadening based on my selection. What am I doing wrong?
library(shinydashboard)
library(tidyverse)
library(plotly)
library(shiny)
#______________________________________________________________________________#
server <- function(input, output, session) {
df <- reactive({
subset(iris, Petal.Width == input$Petalw)
})
# Extract list of Petal Lengths from selected data - to be used as a filter
p.lengths <- reactive({
unique(df()$Petal.Length)
})
# Filter based on Petal Length
output$PetalL <- renderUI({
selectInput("PetalLengthSelector", "PetalLength", as.list(p.lengths()))
})
# Subset this data based on the values selected by user
df_1 <- reactive({
foo <- subset(df(), Petal.Length == input$PetalLengthSelector)
return(foo)
})
output$table <- DT::renderDataTable(
DT::datatable(df_1(), options = list(searching = FALSE,pageLength = 25))
)
output$correlation_plot <- renderPlotly({
plot1 <- plot_ly(data=df_1(),
x = ~Petal.Length,
y = ~Petal.Width,
type = 'scatter',
mode = 'markers'
)
})
}
#______________________________________________________________________________#
ui <- navbarPage(
title = 'Select values in two columns based on two inputs respectively',
fluidRow(
column(width = 12,
plotlyOutput('correlation_plot')
)
),
fluidRow(
column(width = 3,
selectInput("Petalw","PetalWidth", choices = unique(iris$Petal.Width),multiple = T),
uiOutput("PetalL")
),
column(9,
tabPanel('Table', DT::dataTableOutput('table'))
)
)
)
shinyApp(ui, server)

Recomputing renderplot based on renderui user input in RShiny

I'm a bit of an RShiny and R novice. I'm trying to program an RShiny application. It would initially graphs a scatterplot matrix using the first three variables of the dataset by default. The user could then choose their own variable selections from a complete list of variables. Once variables are chosen, the user would click and action button and the graph would be recomputed using the newly selected variables.
I'm using selectinput rather than checkboxinput to accommodate datasets with many variables. I'm using the iris dataset. The code below produces the initial graph and allows the user to select the variables. I just can't figure out how to make it recompute the matrix plot. How do I do this? Thanks!
library(shiny)
runApp(list(
ui = fluidPage(
cols = colnames(iris),
headerPanel('Grow Clusters'),
tabsetPanel(
tabPanel("Plot",
sidebarPanel(
# uiOutput("varselect"),
selectInput("choose_vars", "Select variables to plot",
choices=colnames(iris), selected=iris[1:3], multiple=T),
actionButton("submitButton", "Produce Matrix Plot!")
),
mainPanel(
plotOutput('pairsplot')
)
),
tabPanel("Summary")
,
tabPanel("Table")
)
),
server = function(input, output) {
selectedData <- reactive({
cols = colnames(iris)
selectInput("choose_vars", "Select variables to plot",
choices=cols, selected=cols[1:3], multiple=T)
})
output$pairsplot <- renderPlot({
pairs(iris[1:3], pch = 21)
})
output$varselect <- renderUI({
iris[input$choose_vars]
plotOutput("pairsplot")
})
}
)
)
I think what you are looking for is quo function as in the Chris Beely blog: https://chrisbeeley.net/?p=1116
If you want users to pass arguments and then turn that character vector into objects r can read you need to use quo(input$choose_vars) and then in the plot you need to add !! before that passing variable. Notice you need to load dplyr.
library(shiny)
library(dplyr)
runApp(list(
ui = fluidPage(
cols = colnames(iris),
headerPanel('Grow Clusters'),
tabsetPanel(
tabPanel("Plot",
sidebarPanel(
# uiOutput("varselect"),
selectInput("choose_vars", "Select variables to plot",
choices=colnames(iris), selected=iris[1:3], multiple=T),
actionButton("submitButton", "Produce Matrix Plot!")
),
mainPanel(
plotOutput('pairsplot')
)
),
tabPanel("Summary")
,
tabPanel("Table")
)
),
server = function(input, output) {
selectedData <- reactive({
cols <- colnames(iris)
selectInput("choose_vars", "Select variables to plot",
choices=cols, selected=cols[1:3], multiple=T)
})
output$pairsplot <- renderPlot({
if(is.null(input$choose_vars) || length(input$choose_vars)<2){
pairs(iris[1:3], pch = 21)
} else {
var <- quo(input$choose_vars)
pairs(iris %>% select(!!var), pch = 21)
}
})
output$varselect <- renderUI({
iris[input$choose_vars]
plotOutput("pairsplot")
})
}
)
)

Shiny renderUI with multiple inputs

My Shiny App has multiple inputs that depend on the number of variables used. A simplified version, though not working, is below. I was able to get the UI to update based upon the numericInput using a function called Make.UI which I used to make uiOutput, but getting the inputs back into the server is beyond my Shiny skill set! Any suggestions would be greatly appreciated.
gwynn
library(shiny)
D = matrix(runif(400), nrow = 20)
colnames(D) = labs = sapply(1:20, function(i) {paste0("col",i)})
# Define UI for application that summarises data
ui <- fluidPage(
# Application title
titlePanel("Summaries"),
# Select columns to get fed into summary
tabsetPanel(
tabPanel("Matching Variables Info",
sidebarPanel(
numericInput("NoVars","No. of variables to summarize",
value = 3, min = 2, max = dim(D)[2]),
uiOutput("VarsInput")
),
# Show summaries of columns choosen above
mainPanel(
verbatimTextOutput("dataInfo")
)
)
)
)
# Define the server code
server <- function(input, output){
Make.UI <- function(NoV){
C = sapply(1:NoV, function(i){paste0("cols",i)})
L = sapply(1:NoV, function(i){paste0("label",i)})
output = tagList()
for(i in seq_along(1:NoV)){
output[[i]] = tagList()
output[[i]][[1]] = selectInput(C[i], "Variable to summarize:", labs)
output[[i]][[2]] = textInput(L[i], label = "Label for variable:",
value = "Label for variable Here")
} ## for loop
output
} # closes Make.UI function
K <- reactive({
input$NoVars
})
output$VarsInput <- renderUI({
Make.UI(K())
})
output$dataInfo <- renderPrint({
C <- sapply(1:K(), function(i) {input[[paste0("cols",i)]]})
## the code in the line above doesn't work
summary(D[, C()])
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)
Like I wrote in the first comment, I am unsure about the Make.UI()function. If you really want to keep it as a seperate function you should make it reactive. Or just use it as I did in the code below.
Moreover, in output$dataInfo <- renderPrint({ C is not a reactive() function so you would need to remove brackets there.
library(shiny)
D = matrix(runif(400), nrow = 20)
colnames(D) = labs = sapply(1:20, function(i) {paste0("col",i)})
# Define UI for application that summarises data
ui <- fluidPage(
# Application title
titlePanel("Summaries"),
# Select columns to get fed into summary
tabsetPanel(
tabPanel("Matching Variables Info",
sidebarPanel(
numericInput("NoVars","No. of variables to summarize",
value = 3, min = 2, max = dim(D)[2]),
uiOutput("VarsInput")
),
# Show summaries of columns choosen above
mainPanel(
verbatimTextOutput("dataInfo")
)
)
)
)
# Define the server code
server <- function(input, output){
K <- reactive({
input$NoVars
})
output$VarsInput <- renderUI({
NoV = K()
C = sapply(1:NoV, function(i){paste0("cols",i)})
L = sapply(1:NoV, function(i){paste0("label",i)})
output = tagList()
for(i in seq_along(1:NoV)){
output[[i]] = tagList()
output[[i]][[1]] = selectInput(C[i], "Variable to summarize:", labs)
output[[i]][[2]] = textInput(L[i], label = "Label for variable:",
value = "Label for variable Here")
}
output
})
output$dataInfo <- renderPrint({
C <- sapply(1:K(), function(i) {input[[paste0("cols",i)]]})
## the code in the line above doesn't work
summary(D[, C])
})
}
# Return a Shiny app object
shinyApp(ui = ui, server = server)

Resources