Reputation: 89
I am trying to create an easy application with R shiny. However I could not get the desired output I want. I am neither experienced in shiny nor an expert of R. Here is the code:
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
checkboxGroupInput("plots", "draw plots:",
choices=list("histogram", "qq","both"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=seq(0:5), min=0, max=5),
numericInput("sd","standart deviation",value=seq(0:5),min=0,max=5),
numericInput("n", " number of observations ", value=seq(30,50))
),
mainPanel(
textOutput("text1"),
fluidRow(splitLayout(cellWidths = c("60%", "40%"),
plotOutput("graph1"), plotOutput("graph2")))
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distrubution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$graph1<-renderPlot({
if(identical(input$plots,"histogram")){
req(norm())
hist(norm())
}
})
output$graph2<- renderPlot({
if(identical(input$plots,"qq")) {
req(norm())
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
observe({
if(identical(input$plots,"both")) {
req(norm())
output$graph1<- renderPlot({
hist(norm())
})
output$graph2<- renderPlot({
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
})
}
})
}
shinyApp(ui = ui, server = server)
I want the plot layout change dynamically according to selection of checkboxGroupInput
. When I click histogram
or qq
I want it to plot an unsplit frame, into only one plotting frame. Whereas when I click both
I want the plots to be seen together in a split frame of two rows. When unclicked the layout must be reset to one frame again. I know I am not doing it right by splitting the layout in ui
first. I saw something about renderUI
function but could not understand how it works. Thanks in advance.
Also I got some error related to if statement:
Warning in if (!is.na(attribValue)) { : the condition has length > 1 and only the first element will be used Warning in charToRaw(enc2utf8(text)) : argument should be a character vector of length 1 all but the first element will be ignored
Upvotes: 0
Views: 1281
Reputation: 5966
Here is a start, you don't need the observer, you can just add an if
statement to each renderPlot
.
Update: The trick to getting the plots to update dynamically is to assign them into a list and then render the list of plots with renderUI
, the only caveat to this is that I am unaware of a way to get these plots to render side-by-side at the moment, it probably has something to do with adding some div tags...
Update 2: To get the plots side by side we just need to wrap the plotOutput
in column
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
checkboxGroupInput("plots", "draw plots:",
choices=list("histogram", "qq"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=1, min=0, max=5),
numericInput("sd","standart deviation",value=1,min=0,max=5),
numericInput("n", " number of observations ", value=30)
),
mainPanel(
textOutput("names"),
textOutput("text1"),
fluidRow(uiOutput("plot_list"))
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distribution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$histogram <- renderPlot({
req(norm())
if("histogram" %in% input$plots){
hist(norm())
}
})
output$qq <- renderPlot({
req(norm())
if("qq" %in% input$plots){
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
output$plot_list <- renderUI({
plot_output_list <- lapply(input$plots,
function(plotname) {
column(width=5, plotOutput(plotname)) ##wrap the plotOutput in column to render side-by-side
})
# Convert the list to a tagList - this is necessary for the list of items
# to display properly.
do.call(tagList, plot_output_list)
})
}
shinyApp(ui = ui, server = server)
Upvotes: 1
Reputation: 2816
You can have a single plotOutput
and use mfrow
to split it into two panels, like this:
library(shiny)
ui <- fluidPage(
headerPanel("deneme"),
radioButtons("plots", "draw plots:",
choices=list("histogram", "qq","both"),
selected="histogram"),
sidebarPanel(
numericInput("mean", "rn mean", value=seq(0:5), min=0, max=5),
numericInput("sd","standart deviation",value=seq(0:5),min=0,max=5),
numericInput("n", " number of observations ", value=seq(30,50))
),
mainPanel(
textOutput("text1"),
plotOutput("graph")
)
)
server <- function(input, output) {
norm<-reactive({
set.seed(6)
rnorm(input$n,mean=input$mean,sd=input$sd)
})
output$text1<-renderText({
paste("A random normal distrubution of",
input$n, "observations is generated with parameters mean",
input$mean,"and standart deviation", input$sd)
})
output$graph = renderPlot({
if(input$plots == "both") {
par(mfrow = c(1, 2))
}
if(is.element(input$plots, c("histogram", "both"))) {
req(norm())
hist(norm())
}
if(is.element(input$plots, c("qq", "both"))) {
req(norm())
qqnorm(norm(), pch = 1, frame = FALSE)
qqline(norm(), col = "steelblue", lwd = 2)
}
})
}
shinyApp(ui = ui, server = server)
If you want two rows instead of two columns, just change par(mfrow = c(1, 2))
to par(mfrow = c(2, 1))
.
(I'm still getting the error on if
too, but it doesn't seem to affect the functioning of the app, at least as far as the graphs are concerned. I'm not sure where it's coming from.)
Upvotes: 1