Multiple plots according to checkboxGroupInput - r

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

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)

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.)

Related

How to preserve output and add multiple outputs with Shiny modules?

I would like to preserve the output from one input and then add more outputs.
Code:
if (interactive()) {
ui <- fluidPage(
sidebarPanel(
selectInput("plotType", "Plot Type",
c(Scatter = "scatter", Histogram = "hist")
),
# Only show this panel if the plot type is a histogram
conditionalPanel(
condition = "input.plotType == 'hist'",
selectInput(
"breaks", "Breaks",
c("Sturges", "Scott", "Freedman-Diaconis", "[Custom]" = "custom")
),
# Only show this panel if Custom is selected
conditionalPanel(
condition = "input.breaks == 'custom'",
sliderInput("breakCount", "Break Count", min = 1, max = 50, value = 10)
)
)
),
mainPanel(
plotOutput("plot")
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
output$plot <- renderPlot({
if (input$plotType == "scatter") {
plot(x, y)
} else {
breaks <- input$breaks
if (breaks == "custom") {
breaks <- input$breakCount
}
hist(x, breaks = breaks)
}
})
}
shinyApp(ui, server)
}
Right now the output from "Scatter" disappears if for instance I select "Histogram". I would like to keep the scatter plot and add the histogram below it, and I would like to do this indefinitely.
I tried to do a few things but I didn't know what I needed to look for or learn.
Perhaps, I can add a button called Insert new plot which resets the inputs and saves the recently made plot, and then I can choose new inputs and generate a plot, and so on.
I merged two screenshots to create a picture of what I would like to achieve
Here is a solution that only shows the histogram when the plottype was selected, but keeps the scatter plot and also the histogram once it was selected. For this I use a second plot output and req with a flag if the histogram was already selected.
if (interactive()) {
ui <- fluidPage(
sidebarPanel(
selectInput("plotType", "Plot Type",
c(Scatter = "scatter", Histogram = "hist")
),
# Only show this panel if the plot type is a histogram
conditionalPanel(
condition = "input.plotType == 'hist'",
selectInput(
"breaks", "Breaks",
c("Sturges", "Scott", "Freedman-Diaconis", "[Custom]" = "custom")
),
# Only show this panel if Custom is selected
conditionalPanel(
condition = "input.breaks == 'custom'",
sliderInput("breakCount", "Break Count", min = 1, max = 50, value = 10)
)
)
),
mainPanel(
plotOutput("plot"),
plotOutput("plot_2")
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
hist_flag <- FALSE
output$plot <- renderPlot({
plot(x, y)
})
output$plot_2 <- renderPlot({
req(input$plotType == "hist" || hist_flag)
breaks <- input$breaks
if (breaks == "custom") {
breaks <- input$breakCount
}
hist_flag <<- TRUE
hist(x, breaks = breaks)
})
}
shinyApp(ui, server)
}
Edit
The scenario you describe is a good use-case for modules. I've created a module that contains all the logic and ui to output one plot, and then add another module every time one clicks the button:
library(shiny)
one_plotUI <- function(id) {
ns <- NS(id)
plotOutput(ns("plot"))
}
one_plot <- function(id, x, y, type, breaks, break_counts) {
moduleServer(
id,
function(input, output, session) {
output$plot <- renderPlot({
if (type == "scatter") {
plot(x, y)
} else {
if (breaks == "custom") {
breaks <- break_counts
}
hist(x, breaks = breaks)
}
})
}
)
}
ui <- fluidPage(
sidebarPanel(
selectInput("plotType", "Plot Type",
c(Scatter = "scatter", Histogram = "hist")
),
# Only show this panel if the plot type is a histogram
conditionalPanel(
condition = "input.plotType == 'hist'",
selectInput(
"breaks", "Breaks",
c("Sturges", "Scott", "Freedman-Diaconis", "[Custom]" = "custom")
),
# Only show this panel if Custom is selected
conditionalPanel(
condition = "input.breaks == 'custom'",
sliderInput("breakCount", "Break Count", min = 1, max = 50, value = 10)
)
),
actionButton("make_plot", "Insert new plot")
),
mainPanel(
div(id = "add_here")
)
)
server <- function(input, output) {
x <- rnorm(100)
y <- rnorm(100)
counter_plots <- 1
observeEvent(input$make_plot, {
current_id <- paste0("plot_", counter_plots)
# call the logic for one plot
one_plot(id = current_id,
x = x,
y = y,
type = input$plotType,
breaks = input$breaks,
break_counts = input$breakCount)
# show the plot
insertUI(selector = "#add_here",
ui = one_plotUI(current_id))
# update the counter
counter_plots <<- counter_plots + 1
})
}
shinyApp(ui, server)
Here is a way to create an arbitrary number of plots.
library(tidyverse)
library(shiny)
library(glue)
ui <- fluidPage(actionButton("add_sepal_length", "Add Sepal.Length Histogram"),
actionButton("add_sepal_width", "Add Sepal.Width Histogram"),
uiOutput("plot_ui"))
server <- function(input, output, session){
number_of_plots <- reactiveVal(0L)
output$plot_ui <- renderUI({
req(number_of_plots()>0)
seq(number_of_plots(),1) %>% map(~plotOutput(glue("plot_{.}")))
})
observeEvent(input$add_sepal_length,{
output[[glue("plot_{number_of_plots() +1}")]] <- renderPlot(hist(iris$Sepal.Length))
number_of_plots(number_of_plots() + 1L)
})
observeEvent(input$add_sepal_width,{
output[[glue("plot_{number_of_plots() +1}")]] <- renderPlot(hist(iris$Sepal.Width))
number_of_plots(number_of_plots() + 1L)
})
}
shinyApp(ui = ui, server = server)
The basic idea is that you can use renderPlot to add to ouput$ by string. The observeEvent creates the plot on demand. Put whatever plotting logic you want in here. This takes care of the server part. The UI is handled by a single renderUI which returns a list of plotOutputs.
My logic here is very simple. I use a map() function which only needs to know the id. You could do something fancy involving a whole lot of parameters. One time I did a project where I had arbitrarily many selectInputs. I stored the parameters in a tibble inside of a reactiveVal and used pmap() inside the renderUI.

Problem in showing a graph on Shiny: combining clustering and linear regression

I expanded the result from my last question with a new idea.
Error in Running R Shiny App: Operation not allowed without an active reactive context
This time in addition to clustered points in Iris data (see my previous question), I want to show the regression line (on the plot), slope & intercept (on the sidebar) for the selected points as in:
The regression code is available here (separate server.R and ui.R files):
library(shiny)
shinyServer(function(input, output) {
model <- reactive({
brushed_data <- brushedPoints(iris, input$brush1,
xvar = "Petal.Length", yvar = "Petal.Width")
if(nrow(brushed_data) < 2){
return(NULL)
}
lm(Petal.Width ~ Petal.Length, data = brushed_data)
})
output$slopeOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][2]
}
})
output$intOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][1]
}
})
output$plot1 <- renderPlot({
plot(iris$Petal.Length, iris$Petal.Width, xlab = "Petal.Length",
ylab = "Petal.Width", main = "Iris Dataset",
cex = 1.5, pch = 16, bty = "n")
if(!is.null(model())){
abline(model(), col = "blue", lwd = 2)
}
})
})
and
library(shiny)
shinyUI(fluidPage(
titlePanel("Visualize Many Models"),
sidebarLayout(
sidebarPanel(
h3("Slope"),
textOutput("slopeOut"),
h3("Intercept"),
textOutput("intOut")
),
mainPanel(
plotOutput("plot1", brush = brushOpts(
id = "brush1"
))
)
)
))
I used the following code. However, I have a problem with merging these two ideas and the plot is not shown:
Here is the main code for this question (server and ui in one file):
# Loading Libraries and data
library(shiny)
library(caret)
library(ggplot2)
data(iris)
ui <- pageWithSidebar(
# heading 1
headerPanel(h1("Clustering Iris Data")),
sidebarPanel(
sliderInput("k", "Number of clusters:",
min = 1, max = 5, value = 3),
sliderInput("prob", "Training percentage:",
min=0.5, max=0.9, value = 0.7),
# bold text
tags$b("Slope:"),
textOutput("slopeOut"),
# empty line
br(),
# bold text
tags$b("Intercept:"),
textOutput("intOut")
),
# Enabling the submit button disables the hovering feature
# submitButton("submit")),
mainPanel(
# img(src='iris_types.jpg', align = "center", height="50%", width="50%"),
plotOutput("plot1",
click = "plot_click",
brush = brushOpts(id = "brush1")
),
verbatimTextOutput("info")
)
)
#----------------------------------------------------------------------------
server <- function(input, output) {
# the clustering part
get_training_data <- reactive({
inTrain <- createDataPartition(y=iris$Species,
p=input$prob,
list=FALSE)
training <- iris[ inTrain,]
testing <- iris[-inTrain,]
kMeans1 <- kmeans(subset(training,
select=-c(Species)),
centers=input$k)
training$clusters <- as.factor(kMeans1$cluster)
training
})
#-------------------------
# the linear model part
model <- reactive({
brushed_data <- brushedPoints(iris, input$brush1,
xvar = "Petal.Length", yvar = "Petal.Width")
if(nrow(brushed_data) < 2){
return(NULL)
}
lm(Petal.Width ~ Petal.Length, data = brushed_data)
})
# reactive
output$slopeOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][2]
}
})
# reactive
output$intOut <- renderText({
if(is.null(model())){
"No Model Found"
} else {
model()[[1]][1]
}
})
#------------------------------------------------
# if (x()<4) 1 else 0
output$plot1 <- reactive({
if(is.null(model())) {
# If no regression model exists, show the regular scatter plot
# with clustered points and hovering feature
renderPlot({
plot(Petal.Width,
Petal.Length,
colour = clusters,
data = get_training_data(),
xlab="Petal Width",
ylab="Petal Length")
})
output$info <- renderPrint({
# With ggplot2, no need to tell it what the x and y variables are.
# threshold: set max distance, in pixels
# maxpoints: maximum number of rows to return
# addDist: add column with distance, in pixels
nearPoints(iris, input$plot_click, threshold = 10, maxpoints = 1,
addDist = FALSE)
})
# closing if
}
else
# If there is a regression model, show the plot with the regression line for the brushed points
renderPlot({
plot(Petal.Width,
Petal.Length,
colour = clusters,
data = get_training_data(),
xlab = "Petal.Length",
ylab = "Petal.Width",
main = "Iris Dataset",
cex = 1.5, pch = 16, bty = "n")
if(!is.null(model())){
abline(model(), col = "blue", lwd = 2)
}
})
# closing reactive statement
})
# curly brace for server function
}
shinyApp(ui, server)
You were assigning the wrong data type to the output$plot1.
It expects something that was created by the function renderPlot(...) while you were giving it a result of reactive(...).
Restructure your code such that you immediately assign
output$plot1 <- renderPlot(...)
Since renderPlot opens a reactive environment, just as reactive does, you can just replace the function. But make sure that you remove the renderPlot calls from within the environment.
After changing that, you will run into some more errors you have in your code but I bet you can work it out from there.

Interacting with checkboxes in Rshiny for overlapping plots

I am struggling trying to graph two overlaying plots and add checkboxes fro displaying them in my Rshiny app. I am using the following code:
library(shiny)
library(shinyjs)
mpgData <- mtcars
ui <- fluidPage(
# Application title
titlePanel("Test"),
# Sidebar with checkboxes to select plot
sidebarLayout(
sidebarPanel(
helpText("Select type of plot:"),
checkboxGroupInput("checkPlot",
label = ("Plots"),
choices=c("Baseline","Scenario A"),
selected = c("Baseline","Scenario A")
)
),
mainPanel(
textOutput("overview"),
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
#get Check group input (type of plot)
checkedVal <- reactive({
as.vector(input$checkPlot)
})
#plot
output$plot <- renderPlot({
if(("Baseline" %in% checkedVal()) & ("Scenario A" %in% checkedVal()))
# first plot
plot(mpgData$mpg, mpgData$cyl, type='l',col="steelblue",ylim=range(c(mpgData$cyl,mpgData$disp)))
# second plot
par(new = TRUE)
plot(mpgData$mpg, mpgData$disp, type = "l",col="red", ylim=range(c(mpgData$cyl,mpgData$disp)), axes = FALSE, xlab = "", ylab = "")
if ("Baseline" %in% checkedVal())
plot(mpgData$mpg, mpgData$cyl, type='l',col = "steelblue")
if ("Scenario A" %in% checkedVal())
plot(mpgData$mpg, mpgData$disp, type='l',col = "red")
})
}
shinyApp(ui, server)
My checkboxes seem to be working out alright when I just want one graph to be displayed, however, there's definitely an issue when I want to display both on the same axes. Most examples I saw were a little too complex for me to understand and break down, so I tired to infer from previous R knowledge, but clearly I'm off.
any help is much appreciated !
If you were trying to add the baseline on the existing graph, you could use the lines function, as below. Although if for your particular data-set, the base line is really negligible compared to the original plot, you need to use a package other than 'base', like 'ggplot'.
library(shiny)
library(shinyjs)
mpgData <- mtcars
ui <- fluidPage(
# Application title
titlePanel("Test"),
# Sidebar with checkboxes to select plot
sidebarLayout(
sidebarPanel(
helpText("Select type of plot:"),
checkboxGroupInput("checkPlot",
label = ("Plots"),
choices=c("Baseline","Scenario A"),
selected = c("Baseline","Scenario A")
)
),
mainPanel(
textOutput("overview"),
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
#get Check group input (type of plot)
checkedVal <- reactive({
as.vector(input$checkPlot)
})
#plot
# first plot
output$plot <- renderPlot({
if(("Baseline" %in% checkedVal()) & ("Scenario A" %in% checkedVal()))
{ plot(mpgData$mpg, mpgData$cyl, type='l',col="steelblue",ylim=range(c(mpgData$cyl,mpgData$disp)))
lines(mpgData$mpg, mpgData$disp, type = "l",col="red")
}
else if("Baseline" %in% checkedVal())
{
plot(mpgData$mpg, mpgData$cyl, type='l',col = "steelblue")
}
else if("Scenario A" %in% checkedVal())
{
plot(mpgData$mpg, mpgData$disp, type='l',col = "red")
}
})
}
shinyApp(ui, server)
Please let me know if this works for you.

Is it possible to have different types of output in shiny R?

I've been thinking if there's an answer to the question.
So i have this code in server.R
desc <- reactive({
for (i in 1:input$txt1){
print(paste("Cluster ke", i))
clust <- ensemble()
newdata <- clust[which(clust$Cluster==i), 1]
print(paste(newdata))
barm <- vector("numeric")
x <- ncol(clust)-2
for (j in 2:x){
datdesc <- clust[which(clust$Cluster==i), j]
m <- mean(datdesc)
colnam <- colnames(clust[j])
print(paste("Rata-rata produktivitas", colnam,":", m))
for(k in j-1){
barm[k] <- m
}
}
print(paste(barm))
barplot(barm)
}
})
output$desc <- renderPrint({
desc()
})
And this in the ui
conditionalPanel(condition="input.choice==3", verbatimTextOutput("desc"))
So far, i can get all the output i wanted, the descriptive text and the bar plot. But, the bar plot is appears at the R console instead on the browser.
Is there any way to make the text and barplot show up at the same page?
Can i use other function of renderPrint or verbatimTextOutput that possibly can do that?
Or any other ways?
I've been thinking some solution to this, like dividing the desc() so it has two outputs, text and barplot. But if there's a way to make it in one go, I'm very much want to learn that way.
Sure, it's common to have many different output types. Please see the Shiny gallery for more examples.
Based on the code you provided and a template:
UI.R
bootstrapPage(
selectInput(
"choice", "txt1 - descriptive text?",
c(my_text = "my_text",
your_text = "your_text")),
selectInput(inputId = "n_breaks",
label = "Number of bins in histogram (approximate):",
choices = c(10, 20, 35, 50),
selected = 20),
checkboxInput(inputId = "individual_obs",
label = strong("Show individual observations"),
value = FALSE),
checkboxInput(inputId = "density",
label = strong("Show density estimate"),
value = FALSE),
plotOutput(outputId = "main_plot", height = "300px"),
conditionalPanel(condition="input.choice=='my_text'", verbatimTextOutput("desc"))
)
Server.R
function(input, output) {
desc <- reactive({
"some text goes here, I guess!"
})
output$desc <- renderPrint({
desc()
})
output$main_plot <- renderPlot({
hist(faithful$eruptions,
probability = TRUE,
breaks = as.numeric(input$n_breaks),
xlab = "Pandjie Soerja",
main = "Pandjie Soerja")
if (input$individual_obs) {
rug(faithful$eruptions)
}
if (input$density) {
dens <- density(faithful$eruptions,
adjust = input$bw_adjust)
lines(dens, col = "blue")
}
})
}

Shiny: Error in plot.window: need finite 'xlim' values on page load

I am trying to create a barplot in R shiny. Data are coming from a csv file and they are filtered according to user's selection in selectInput and sliderInput controls.
When the page is loading I am getting the error:
Error in plot.window: need finite 'xlim' values.
Then, when the page is fully loaded, all is fine and working.
It looks like the first time app runs, popData which I pass to function barplot is null. I was trying to check if popData is null as advised here before rendering plot but still getting the same error. When I use hard-coded values for selectedCountry and selectedYear instead of reactive expressions, it works okay, I do not get this initial error what makes me think results of selectInput and sliderInput may not available yet when plot is rendered first time(?)
How can I fix this? Thanks.
ui <- fluidPage(
titlePanel(title = h3("Population by age")),
sidebarLayout(
sidebarPanel(
uiOutput("geoSelector"),
br(),
uiOutput("yearSlider"),
br()
),
mainPanel(
plotOutput("barChart"),
br()
))
)
server <- function(input, output) {
data <- read.csv("data.csv")
geo = sort(unique(data[,"GeographyName"]))
output$geoSelector <- renderUI({
selectInput("country", "Select country", as.list(geo))
})
minY <- min(unique(data[,"PeriodValue"]))
maxY <- max(unique(data[,"PeriodValue"]))
output$yearSlider <- renderUI({
sliderInput("year", "Select year", min=minY, max=maxY,
value=as.integer(format(Sys.Date(), "%Y")), sep="", animate = TRUE, step=1)
})
selectedCountry <- reactive({input$country})
selectedYear <- reactive({input$year})
selectedData <- reactive({subset(data, GeographyName == selectedCountry() &
PeriodValue == selectedYear())})
selectedDataSorted <- reactive({selectedData()[order(selectedData()$AgeCategoryId),c(1:8)]})
popData <- reactive({selectedDataSorted()$DataPoint})
categ <- reactive({selectedDataSorted()$AgeCategory})
output$barChart <- renderPlot({
barplot(popData(),names.arg=categ(), cex.names = 0.7, border=NA,
xlab="Age Category", ylab="Population (m)")
})
}
shinyApp(ui = ui, server = server)
Does this solve your issue?
output$barChart <- renderPlot({
validate(need(nrow(popData())>0, "Please select a data set"))
barplot(popData(),names.arg=categ(), cex.names = 0.7, border=NA,
xlab="Age Category", ylab="Population (m)")
})

Resources