I'm new to R. I have a large dataset that I want the user to be able to select the x values plotted on a graph. To make it easier, I've done the same thing using the mpg dataset:
library(shiny)
ui <- fluidPage(
selectInput(
inputId= "manuf",
label= "Manufacturer",
choices= mpg$manufacturer,
multiple= TRUE
),
plotOutput("graph1")
)
server <- function(input, output) {
output$graph1 <- renderPlot({
ggplot() +
geom_point (
mapping = aes (
x= input$manuf,
y= ???
)
)
})
}
shinyApp(ui = ui, server = server)
I can't for the life of me figure out what the correct syntax is for the 'y' input. I have been googling my heart out and can't figure it out, and I'm sure it's relatively simple. I want it to only output the data for whatever you've selected in the drop down.
putting in y= mpg$hwy shows ALL hwy datapoints when one manufacturer is selected and throws an error ("Aesthetics must be either length 1 or the same as the data") with more. I think the errors are self-explanatory, but that doesn't help me figure out the correct code for 'y'. Ideas? Thanks in advance.
The aesthetic mappings for ggplot (like aes(x = ...)) should be column names, but you aren't giving the user a choice of column names, you give the user the choice of manufacturer values---which correspond to rows. If you want the user to select certain rows to plot based on the manufacturer, you should subset/filter the data that you give to ggplot, perhaps like this:
library(shiny)
library(ggplot2)
ui <- fluidPage(
selectInput(
inputId = "manuf",
label = "Manufacturer",
choices = mpg$manufacturer,
multiple = TRUE
),
plotOutput("graph1")
)
server <- function(input, output) {
output$graph1 <- renderPlot({
ggplot(data = mpg[mpg$manufacturer %in% input$manuf, ]) +
geom_point (
mapping = aes (
x = manufacturer,
y = hwy
)
)
})
}
shinyApp(ui = ui, server = server)
Let's forget about Shiny for a moment and focus on how you would filter a dataset for plotting with ggplot(). The tidyverse approach is to use dplyr::filter:
library(dplyr)
library(ggplot2)
mpg %>%
filter(manufacturer == "audi") %>%
ggplot(aes(manufacturer, hwy)) +
geom_point()
So your server function would look something like this (untested):
server <- function(input, output) {
output$graph1 <- renderPlot({
mpg %>%
filter(manufacturer == input$manuf) %>%
ggplot(aes(manufacturer, hwy)) +
geom_point()
)}
}
Related
I am trying to make a shiny app that will allow to color the points of the scatterplot based on the selected categorical variables.
library(shiny)
data<-data.frame(iris)
ui <- navbarPage("Summary",
tabsetPanel(
tabPanel("Graph", fluid=T,
fluidPage(
sidebarPanel(selectInput(inputId = "varColor",
label = "Color",
choices = c("Species", "Other_Category"),
selected = "Species")),
mainPanel(plotOutput(outputId = "plot"))
)
)
)
)
server <- function(input, output) {
p<-reactive({ggplot(data,
aes(y = Sepal.Length, x = Petal.Length))+
# This Part needs help
geom_point(aes( input$varColor)) })
output$plot <- renderPlot({
p()
})
}
shinyApp(ui, server)
I think that now, the program reads the color selection from the input as a string, instead of taking it as category.
Thank you for help.
The issue is that input$colorVar is simply a character. Hence, ggplot2 will treat this character value as the one and only category. Hence, you end up with one color.
To tell ggplot2 that it should color the plot according to the data column whose named is stored in input$colorVar you could make use of the so called .data pronoun provided by the rlang package, i.e. do aes(color = .data[[input$varColor]]):
library(shiny)
library(ggplot2)
data <- data.frame(iris)
ui <- navbarPage(
"Summary",
tabsetPanel(
tabPanel("Graph",
fluid = T,
fluidPage(
sidebarPanel(selectInput(
inputId = "varColor",
label = "Color",
choices = c("Species", "Other_Category"),
selected = "Species"
)),
mainPanel(plotOutput(outputId = "plot"))
)
)
)
)
#> Warning: Navigation containers expect a collection of `bslib::nav()`/
#> `shiny::tabPanel()`s and/or `bslib::nav_menu()`/`shiny::navbarMenu()`s. Consider
#> using `header` or `footer` if you wish to place content above (or below) every
#> panel's contents.
server <- function(input, output) {
p <- reactive({
ggplot(
data,
aes(y = Sepal.Length, x = Petal.Length)
) +
# This Part needs help
geom_point(aes(color = .data[[input$varColor]]))
})
output$plot <- renderPlot({
p()
})
}
shinyApp(ui, server)
#>
#> Listening on http://127.0.0.1:3070
I am building a shiny application with several tabs, each tab takes a user input (unique(data_in$cat), and generates some type of graph. The problem occurs in the second tab--for some reason, it does not generate the graph that is specified by data2. The first graph on the first tab is being displayed correctly.I see no error when I run this code, so I don't know where to start debugging!
library(shiny)
library(openxlsx)
library(ggplot2)
data_in <- read.xlsx("www/dem_data_clean.xlsx")
ui <- navbarPage(title = "Data",
tabPanel(title = "Over-all trends",
plotOutput("Histall"),
selectInput("Indall","Demographic Variable of Interest",choices = unique(data_in$cat))
),
tabPanel(title = "2017-2018"),
plotOutput("Hist17"),
selectInput("Ind17","Demographic Variable of Interest",choices = unique(data_in$cat))
)
server <- function(input, output, session) {
data1 <- reactive({
a <- subset(data_in,cat==input$Indall)
return(a)
})
data2 <- reactive({
a <- subset(data_in,cat==input$Ind17)
return(a)
})
output$Histall <- renderPlot({
ggplot(data1(), aes(x=Year,y=value, group =name, color=name)) + geom_line(stat = "identity") +
ylab("Percent of Population")
})
output$Hist17 <- renderPlot({
data2() %>%
filter(Year=="2017-18") %>%
ggplot(aes(name, value)) + geom_bar(stat = "identity")
})
}
shinyApp(ui, server)
Any suggestions to what I am doing wrong? I've tried playing around with different things for a few hours now to no avail!
The UI code is not correct, second plotOutput and selectInput are not within second tabPanel. It works if you fix it :
ui <- navbarPage(title = "Data",
tabPanel(title = "Over-all trends",
plotOutput("Histall"),
selectInput("Indall",
"Demographic Variable of Interest",
choices = unique(data_in$cat))
),
tabPanel(title = "2017-2018",
plotOutput("Hist17"),
selectInput("Ind17",
"Demographic Variable of Interest",
choices = unique(data_in$cat)))
)
I want to start a shiny app for practice where a use can choose from a dropdown the values in the "cut" column from the diamonds dataset (from ggplot2).
My ui looks as following:
library(shiny)
# Define UI for application that draws a histogram
shinyUI(fluidPage(
# Application title
titlePanel("Reactive Boxplot"),
# Show a boxplot of the selected cut
mainPanel(
selectInput("column", label = h3("Column to plot"),
choices = c("", diamonds$cut),
selected = 1,
width='55%',
multiple = FALSE),
plotOutput("diamondshist")
)
)
)
I don't know how to define the input variables as the five distinct values in the "cut" column of diamonds dataset. Any input on this?
My server file looks like shared below. I assume I would also need to adapt the input data for the plot.
library(shiny)
library(ggplot2)
# Define server logic required to draw a histogram
shinyServer(function(input, output) {
compute_plot <- reactive({
if (input$column != ""){
ggplot(diamonds[, input$column])+
labs(title = "From diamonds dataset")+
geom_boxplot(aes(x = cut, y = price))+
scale_y_reverse()
}
})
output$diamondshist <- renderPlot({
compute_plot();
})
})
I assume this is what you are after:
pass the levels of diamonds$cut as input selection
subset the diamonds dataset to the selected cut
library(shiny)
library(ggplot2)
# Define UI for application that draws a histogram
ui=shinyUI(fluidPage(
# Application title
titlePanel("Reactive Boxplot"),
# Show a boxplot of the selected cut
mainPanel(
selectInput("column", label = h3("Column to plot"),
choices = c("", levels(diamonds$cut)),
selected = NULL,
width='55%',
multiple = FALSE),
plotOutput("diamondshist")
)
)
)
# Define server logic required to draw a histogram
server=shinyServer(function(input, output) {
compute_plot <- reactive({
if (input$column != ""){
ggplot(subset(diamonds, cut==input$column))+
labs(title = "From diamonds dataset")+
geom_boxplot(aes(x = cut, y = price))+
scale_y_reverse()
}
})
output$diamondshist <- renderPlot({
compute_plot();
})
})
shinyApp(ui = ui, server = server)
I have the following code and would essentially like to take two inputs and return an outplot of a plot with time on the x-axis and the y axis being a ratio of input1/input2. I have tried with aes and aes_string but can not seem to get a working block displaying the ratio inside the shiny app. (Have no problems plotting input1 against year.
ui <- navbarPage("y",
tabPanel('Teacher Type Comparison',
sidebarLayout(
sidebarPanel(
selectInput('teacherInputOne', 'Compare ratio of',
choices = teacher_inputs, selected = 'male_total_staff'),
selectInput('teacherInputTwo', 'to ratio of:',
choices = teacher_inputs, selected = 'female_total_staff'),
checkboxGroupInput('teacherState','States / Territories',area_names)
),
mainPanel(
plotOutput('teacherTypePlot'))
)
)
)
server <- function(input, output) {
output$teacherTypePlot <- renderPlot({
ggplot(data = data, aes(x= year, y = (input$teacherInputOne / input$teacherInputTwo))) + geom_line(aes(colour = state))
})}
shinyApp(ui = ui, server = server)
I am not sure I fully understand all of your variables, based on the code provided, but I would change the server to filter your data based on the input selections in the UI to pass the filtered values to your Y aes. I have only proposed changing code in the server:
server <- function(input, output) {
output$teacherTypePlot <- renderPlot({
data <- data %>%
filter(var1 == input$teacherInputOne,
var2 == input$teacherInputTwo)
ggplot(data = data, aes(x= year, y = var3)) +
geom_line(aes(colour = state))
})}
I have a shiny app with a reactive bit of UI which is used to filter my data. I then use the data for plotting. My reactive bit of UI checks all possible values of a variable, offers them as choices in a selectizeInput and starts with all of the choices selected. In my actual app changes in the filter can take quite a bit of time to run so I have submitButton to prevent the app from constantly updating. The only problem is on the initial startup of the app: It loads the choices in to the dynamic UI and selects them, but because further reactivity is blocked by the submitButton, this information doesn't reach the plot and so it shows an empty plot. All that's needed to get the desired result is hit the sumbitButton once. Once this is done the app works as desired.
I'm looking for a way to make the plot show initially without having to press the submitButton. In my following toy example this could probably be done quite easily by replacing the submitButton with an actionButton so that not all reactivity is frozen, which seems to be the solution in a lot of problems involving submitButtons in other question. However, in my actual app there are numerous inputs and sources of reactivity so configuring the actionButton and capturing all desired effects in observeEvents would be quite tedious when the submitButton does all of this with the only problem being the startup. Are there any other ways I can make the plot show on the first startup but follow the submitButton behavior from then on?
An example app:
library(shiny)
library(ggplot2)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
uiOutput("Cylselectui"),
submitButton("Apply changes")
),
mainPanel(
plotOutput("Carsplot")
)
)
)
server <- function(input, output) {
output$Carsplot <- renderPlot({
plotdata <- subset(mtcars, cyl %in% input$Cylselection) #Filter based on cyl
ggplot(plotdata, aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
geom_point()
})
output$Cylselectui <- renderUI({ #Create the cyl selectize ui based on the values of cyl that are in the data
selectizeInput(
'Cylselection', 'Select by Cylinder',
choices = sort(unique(mtcars$cyl)),
selected = sort(unique(mtcars$cyl)),
multiple = TRUE
)
})
}
shinyApp(ui = ui, server = server)
You can use a reactive to check whether the input is null (first time) and then provide your defaults values:
Cylselection <- reactive({
if(is.null(input$Cylselection))
sort(unique(mtcars$cyl))
else
input$Cylselection})
output$Carsplot <- renderPlot({
plotdata <- subset(mtcars, cyl %in% Cylselection()) #Filter based on cyl
ggplot(plotdata, aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
geom_point()
})
More elegant is to put your data subset in the reactive:
plotdata <- reactive({
if(is.null(input$Cylselection))
mtcars
else
subset(mtcars, cyl %in% input$Cylselection)})
output$Carsplot <- renderPlot({
ggplot(plotdata(), aes(x = mpg, y = hp, colour = factor(cyl))) + #Create plot
geom_point()
})