How can put multiple plots side-by-side in shiny r?
Solution 1
So it is a couple years later, and while the others answers - including mine - are still valid, it is not how I would recommend approaching it today. Today I would lay it out using the grid.arrange
from the gridExtra
package.
- It allows any number of plots, and can lay them out in a grid checkerboard-like. (I was erroneously under the impression
splitLayout
only worked with two). - It has more customization possibilities (you can specify rows, columns, headers, footer, padding, etc.)
- It is ultimately easier to use, even for two plots, since laying out in the UI is finicky - it can be difficult to predict what Bootstrap will do with your elements when the screen size changes.
- Since this question gets a lot of traffic, I kind of think more alternative should be here.
The cowplot
package is also worth looking into, it offers similar functionality, but I am not so familiar with it.
Here is a small shiny program demonstrating that:
library(shiny)
library(ggplot2)
library(gridExtra)
u <- shinyUI(fluidPage(
titlePanel("title panel"),
sidebarLayout(position = "left",
sidebarPanel("sidebar panel",
checkboxInput("donum1", "Make #1 plot", value = T),
checkboxInput("donum2", "Make #2 plot", value = F),
checkboxInput("donum3", "Make #3 plot", value = F),
sliderInput("wt1","Weight 1",min=1,max=10,value=1),
sliderInput("wt2","Weight 2",min=1,max=10,value=1),
sliderInput("wt3","Weight 3",min=1,max=10,value=1)
),
mainPanel("main panel",
column(6,plotOutput(outputId="plotgraph", width="500px",height="400px"))
))))
s <- shinyServer(function(input, output)
{
set.seed(123)
pt1 <- reactive({
if (!input$donum1) return(NULL)
qplot(rnorm(500),fill=I("red"),binwidth=0.2,main="plotgraph1")
})
pt2 <- reactive({
if (!input$donum2) return(NULL)
qplot(rnorm(500),fill=I("blue"),binwidth=0.2,main="plotgraph2")
})
pt3 <- reactive({
if (!input$donum3) return(NULL)
qplot(rnorm(500),fill=I("green"),binwidth=0.2,main="plotgraph3")
})
output$plotgraph = renderPlot({
ptlist <- list(pt1(),pt2(),pt3())
wtlist <- c(input$wt1,input$wt2,input$wt3)
# remove the null plots from ptlist and wtlist
to_delete <- !sapply(ptlist,is.null)
ptlist <- ptlist[to_delete]
wtlist <- wtlist[to_delete]
if (length(ptlist)==0) return(NULL)
grid.arrange(grobs=ptlist,widths=wtlist,ncol=length(ptlist))
})
})
shinyApp(u,s)
Yielding:
Solution 2
Using @Mike Wise example, you can also use splitLayout(cellWidths = c("50%", "50%")...to show two plots side by side.
ui..R
library(shiny)
shinyUI(fluidPage(
titlePanel("title panel"),
sidebarLayout(position = "left",
sidebarPanel("sidebar panel",
checkboxInput("do2", "Make 2 plots", value = T)
),
mainPanel("main panel",
fluidRow(
splitLayout(cellWidths = c("50%", "50%"), plotOutput("plotgraph1"), plotOutput("plotgraph2"))
)
)
)
)
)
server.R
shinyServer(function(input, output)
{
set.seed(1234)
pt1 <- qplot(rnorm(500),fill=I("red"),binwidth=0.2,title="plotgraph1")
pt2 <- reactive({
input$do2
if (input$do2){
return(qplot(rnorm(500),fill=I("blue"),binwidth=0.2,title="plotgraph2"))
} else {
return(NULL)
}
})
output$plotgraph1 = renderPlot({pt1})
output$plotgraph2 = renderPlot({pt2()})
}
)
you can also play with the numbers the figure below shows c("60%", "40%")
EDIT: It is true that @Mike Wise new answer's gives some flexibility. But splitLayout
can also be used with more than two plots. Using cellWidths
allows you to change the size of each individual plot. And verticalLayout()
can also be used to add plots vertically (see comment section).
library(shiny)
library(ggplot2)
u<- shinyUI(fluidPage(
titlePanel("title panel"),
sidebarLayout(position = "left",
sidebarPanel("sidebar panel",
checkboxInput("do2", "Make 2 plots", value = T)
),
mainPanel("main panel",
fluidRow(
splitLayout(style = "border: 1px solid silver:", cellWidths = c(300,200,100),
plotOutput("plotgraph1"),
plotOutput("plotgraph2"),
plotOutput("plotgraph3")
)
)
)
)
)
)
s <- shinyServer(function(input, output){
set.seed(1234)
pt1 <- qplot(rnorm(500),fill=I("red"),binwidth=0.2,title="plotgraph1")
pt3 <- qplot(rnorm(600),fill=I("blue"),binwidth=0.2,title="plotgraph3")
pt2 <- reactive({
input$do2
if (input$do2){
return(qplot(rnorm(500),fill=I("blue"),binwidth=0.2,title="plotgraph2"))
} else {
return(NULL)
}
})
output$plotgraph1 = renderPlot({pt1})
output$plotgraph2 = renderPlot({pt2()})
output$plotgraph3 = renderPlot({pt3}
)
})
shinyApp(u,s)
Solution 3
Well, you did not exactly give us a complete example, but I think this is what you want:
ui.r
# ui.R
shinyUI(fluidPage(
titlePanel("title panel"),
sidebarLayout(position = "left",
sidebarPanel("sidebar panel",
checkboxInput("do2", "Make 2 plots", value = T)
),
mainPanel("main panel",
fluidRow(
column(6,plotOutput(outputId="plotgraph1", width="300px",height="300px")),
column(6,plotOutput(outputId="plotgraph2", width="300px",height="300px"))
)
)
)
)
)
server.r
# server.r
library(ggplot2)
shinyServer(function(input, output)
{
set.seed(1234)
pt1 <- qplot(rnorm(500),fill=I("red"),binwidth=0.2,title="plotgraph1")
pt2 <- reactive({
input$do2
if (input$do2){
return(qplot(rnorm(500),fill=I("blue"),binwidth=0.2,title="plotgraph2"))
} else {
return(NULL)
}
})
output$plotgraph1 = renderPlot({pt1})
output$plotgraph2 = renderPlot({pt2()})
}
)
Output
"Make 2 plots" checked:
"Make 2 plots" unchecked:
Related videos on Youtube
can.u
Updated on July 09, 2022Comments
-
can.u almost 2 years
In mainpanel, I try to handle this problem via fluidrow. However, one of my plot is optional to be displayed or not by users. When user clicks the button, the second plot appears below the first plot.
fluidRow( column(2, align="right", plotOutput(outputId = "plotgraph1", width = "500px",height = "400px"), plotOutput(outputId = "plotgraph2", width = "500px",height = "400px") ))
I played with "align" and "widths", but nothing changed.
-
Mike Wise over 8 yearsNice one. +1 for you :)
-
Mike Wise over 8 yearsHe should have given me a +1 as well. And you for that matter.
-
Liza about 8 yearsIs it possible to divide it into 4 equal parts and have a 2 by 2 matrix with 4 plots?
-
MLavoie about 8 years@liza, actually yes it's possible. You just need to use fluidRow( verticalLayout( splitLayout(cellWidths = c("50%", "50%"), plotOutput("distPlot"), plotOutput("distPlot2")), splitLayout(cellWidths = c("50%", "50%"), plotOutput("distPlot3"), plotOutput("distPlot4"))
-
clesiemo3 about 7 yearssuper useful for my use case of a DataTable and a plot side by side where grid.arrange() won't work. Thanks!
-
Ed_Gravy almost 2 yearsDoes
grid.arrange
work withrenderPlotly
on two out of five plots in the mainpanel?