I want the plots (generated by plotly) to be laid out in two columns and n rows. The number of rows depends on the number of plots. For instance, the layout should be 3(row) x 2(col) if there are 5 or 6 plots. However, there are two problems with the following code. First, only one of them is repeated when we have multiple plots. Second, they are stacked on top of each other, although the column width is 6.
Here is the code:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
for (x in input$xvars){
plt_list[[x]] <- renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
}
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(column(6, plt_list[1:length(input$xvars)]))
}
return(plottoUI)
})
}
shinyApp(ui, server)
UPDATTE:
@lz100 seems to have resolved the main issue with the layout. Here is a further update on how to prevent one plot being repeated. I replaced the for loop
(I don't know the reason why it didn't work) with lapply
.
plt_list <- lapply(input$xvars, function(x){
renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
})
So, considering the @lz100 suggestion the final solution will be:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
plt_list <- lapply(input$xvars, function(x){
renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
})
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(
lapply(1:length(input$xvars), function(x) column(6, plt_list[x]))
)
}
return(plottoUI)
})
}
shinyApp(ui, server)
You need to wrap each plot with a column
, not a column
for all plots, see below:
library(shiny)
library(ggplot2)
library(plotly)
library(dplyr)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(selectInput(inputId = "y", label = "Y", choices = names(mtcars), selected = names(mtcars)[1], multiple = F),
selectizeInput(inputId = "xvars", label = "X", choices = names(mtcars), selected = names(mtcars)[1],
multiple = T)),
mainPanel(uiOutput("allplots"))
)
)
server <- function(input, output, session) {
output$allplots <- renderUI({
plt_list <- list()
for (x in input$xvars){
plt_list[[x]] <- renderPlotly({
mtcars %>% ggplot(aes_string(x = x, y = input$y)) + geom_point()
})
}
if (length(input$xvars) == 1) {
plottoUI <- fluidRow(column(12, plt_list[1]))
} else {
plottoUI <- fluidRow(
lapply(1:length(input$xvars), function(x) column(6, plt_list[x]))
)
}
return(plottoUI)
})
}
shinyApp(ui, server)