I have just learning R shiny package and for one of the exercise in a course, we have to create an app that has two dropdown menus in the sidebar and a ggplot2 plot in the main panel
I almost figured out most of the R code but i am getting error (object 'input' not found) during plotting. Can someone point to me of where i am doing wrong?
ui.R
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Demonstration of 2 dropdown menus"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput("element_id1", "select variable for x-axis", c("mpg", "cyl", "disp", "hp", "wt"), selected = "wt"),
selectInput("element_id2", "select variable for x-axis", c("mpg", "cyl", "disp", "hp", "wt"), selected = "mpg")
),
# Show a plot of the generated distribution
mainPanel(
textOutput("id1"),
textOutput("id2"),
plotOutput("plt")
)
)
))
server.R
library(shiny)
library(ggplot2)
shinyServer(function(input, output) {
output$id1 <- renderText({
sprintf("You have selected %s on the x-axis", input$element_id1)
})
output$id2 <- renderText({
sprintf("You have selected %s on the y-axis", input$element_id2)
})
output$plt <- renderPlot(
ggplot(mtcars, aes(x = input$element_id1, y = input$element_id2)) + geom_point()
)
})
You are providing character variable to mention which are your axis in ggplot. Hence you need to use aes_string when you build your graph:
ggplot(mtcars, aes_string(x = input$element_id1, y = input$element_id2)) + geom_point()
Dummy example:
df = data.frame(x=1:3, y=c(4,5.6,1))
ggplot(df, aes(x=x, y=y)) + geom_line()
ggplot(df, aes_string(x='x', y='y')) + geom_line()
Both provide the same results.
Related
I want to build a shiny app using Covid-19 data (https://data.europa.eu/euodp/de/data/dataset/covid-19-coronavirus-data) and I would like to show barplot with ggplot where you can see the development of worldwide cases or deaths over time. I would furthermore like to have a dateRangeInput in which you can set a time period. At the same time I have on the y axis either the possibility to choose from selectInput either the variable "cases" or "deaths". I can do this separately but I can't figure out how to have this in one final plot.
It works with the time range if I use this code:
ui <- fluidPage(
titlePanel("Covid-19 by Country"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "y", label = "Y-Axe:",
choices=c("cases", "deaths"),
selected = "cases"),
dateRangeInput("datum", "Zeitraum auswählen", start = min(covid_worldwide$dateRep), end = max(covid_worldwide$dateRep), min = min(covid_worldwide$dateRep), max = max(covid_worldwide$dateRep), format = "dd.mm.yyyy", language = "de")
),
mainPanel(
plotOutput("covidPlot")
)
)
)
server <- function(input, output, session) {
s <- reactive({
covid_worldwide %>%
filter(
as.Date(dateRep) >= as.Date(input$datum[1]),
as.Date(dateRep) <= as.Date(input$datum[2])
)
})
output$covidPlot <- renderPlot({
ggplot(data= s(), aes(x = dateRep, y = cases)) +
geom_bar(stat="identity", fill="red") + theme_classic() + xlab("Zeitraum") + ylab("Anzahl")
}
)}
shinyApp(ui = ui, server = server)
It works also if I do not change the time period but give two different variables for the y-axis, see following code (the UI is the same as above):
server <- function(input, output, session) {
s <- reactive({
covid_worldwide %>%
filter(
as.Date(dateRep) >= as.Date(input$datum[1]),
as.Date(dateRep) <= as.Date(input$datum[2])
)
})
yvar <- reactive({
if ( "cases" %in% input$y) return(covid_worldwide$cases)
if ( "deaths" %in% input$y) return(covid_worldwide$deaths)
})
output$covidPlot <- renderPlot({
ggplot(data= s(), aes(x = dateRep, y = yvar())) +
geom_bar(stat="identity", fill="red") + theme_classic() + xlab("Zeitraum") + ylab("Anzahl")
}
)}
shinyApp(ui = ui, server = server)
But if I then try to change the time period in the shiny app I receive this error: "Aesthetics must be either length 1 or the same as the data (26852): y"
Does anyone have an idea on how to make the two things in one ggplot barplot work? Thank you in advance!
You simply have to map input$y on y in your plotting code. Additionally as the input is a character it's convenient to switch to aes_string instead of aes as it allows to pass the variables as names or strings to ggplot().
The first version does not work as you map cases on y. The second one does not work as your reactive yvar extracts a vector from the original unfiltered df. Therefore the length of yvar is greater than the number of rows of the filtered df or the length of your date variable.
output$covidPlot <- renderPlot({
ggplot(data= s(), aes_string(x = "dateRep", y = input$y)) +
geom_bar(stat="identity", fill="red") + theme_classic() + xlab("Zeitraum") + ylab("Anzahl")
}
I work the tea standard dataset in R and wants to create a shiny application in order to represent 2 variables and their %ge frequency.
Here's my R code for ggplot working fine but when i try to encapsulate this code in shiny there seems to be a problem.
ggplot(the, aes(x= clust, group=breakfast)) +
geom_bar(aes(y = ..prop.., fill = factor(..x..)), stat="count") +
geom_text(aes( label = scales::percent(..prop..),y= ..prop.. ), stat= "count", vjust = -.5) +
labs(y = "Percent", fill="clust") +
facet_grid(~breakfast) +
scale_y_continuous(labels = scales::percent)
Here's my shiny ui : very simple and efficient
library(shiny)
# ----- UI ----------------------------
pageWithSidebar(
headerPanel('Representer les variables'),
sidebarPanel(
selectInput('xcol', 'X Variable', names(the)),
selectInput('ycol', 'Y Variable', names(the)),
selected=names(the)[[2]]
),
mainPanel(
plotOutput('plot1')
)
)
Here's my shiny server which doesn't work :
library(shiny)
library(ggplot2)
library(tidyr)
# ---- Server ----------------------------------
server=shinyServer(function(input, output, session) {
selectedData <- reactive({
mutate(group_by(count(the, input$xcol, input$ycol)),
input$xcol, prop = n / sum(n))
})
output$plot1 <- renderPlot({
ggplot(selectedData()) +
geom_col(aes_string(x = input$xcol, y = prop, fill =input$ycol),
position = "dodge")
})
})
How would you implement something like this in R?
Selection histogram
Utilizing the scatterplot selection is the hard part. I haven't seen anything similar in Shiny or plotly.
In case anybody needs it in the future.
ui.R
library(shiny)
library(ggplot2)
shinyUI(basicPage(
titlePanel("Number of forward gears of selected cars"),
plotOutput("plot",brush = "plot_brush"),
plotOutput("histo",height="200px")
))
server.R
library(shiny)
library(ggplot2)
shinyServer(function(input, output) {
output$plot <- renderPlot({
ggplot(mtcars, aes(x=wt, y=mpg,color=as.factor(gear))) + geom_point() + labs(y= 'Miles per gallon',x = 'Weight (1000 lbs)')
})
output$histo <- renderPlot({
selected_points<-brushedPoints(mtcars, input$plot_brush, xvar = "wt", yvar = "mpg")
ggplot(data=selected_points, aes(selected_points$gear,fill = as.factor(gear))) + geom_bar() + labs(x="Forward Gears", y="Count") + coord_flip() +theme_minimal()
})
})
So I am using mpg dataset to practice my R-shiny skills, but I encountered a problem.
I want to write a app which I could choose different variables to make graph, if it involves at least one discrete variable, then I draw a geom_boxplot, else, I will just draw a geom_point.
My ui.R looks like this:
library(shiny)
shinyUI(fluidPage(
# Application title
titlePanel("Old Faithful Geyser Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput(inputId = "var1",
label = "Choose x variable",
choices =
names(mpg)
),
selectInput(inputId = "var2",
label = "Choose y variable",
choices =
names(mpg))
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
And
My server.R looks like this:
library(shiny)
library(tidyverse)
library(dplyr)
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
if(typeof(mpg[, input$var1]) == "chr" ||
typeof(mpg[, input$var2]) == "chr")
{
ggplot(data = mpg) +
geom_boxplot(mapping =
aes(x = mpg[, input$var1],
y = mpg[, input$var2])) +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2))
}
else
{
ggplot(data = mpg) +
geom_point(mapping =
aes(x = mpg[, input$var1],
y = mpg[, input$var2])) +
xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2))
}
})
})
But it simply does not work! When I choose discrete variable, it will return me an error message says "Discrete value applied to continuous scale". However, if I both choose continuous value, it seems to be work fine.
Why it shows such an error message like that?
Please help me!
Thank you very much!
You have a couple of issues here all on the server side:
One: If you check an example of your typeof you'll see that you always get a list:
typeof(mpg[,"model"])
#[1] "list"
typeof(mpg[,"displ"])
#[1] "list"
This is because [ doesn't extract the actual element, but the list containing that element. From ?"[":
Indexing by [ is similar to atomic vectors and selects a list of the specified element(s).
Rather you should use typeof(mpg[[input$var1]]), etc because you want to extract the element of the list (not the list that contains the element).
Two:
There is actually a specific function in ggplot, aes_string which selects the columns to plot based on a string.
Incorporating these two changes should make your shiny app work. I also simplified you server a bit to get rid of the common ggplot code.
server <- function(input,output){
output$distPlot <- renderPlot({
p <- ggplot(mpg) + xlab(input$var1) +
ylab(input$var2) +
ggtitle(paste("Plot", input$var1, "vs", input$var2))
if(typeof(mpg[[input$var1]]) == "character" |
typeof(mpg[[input$var2]]) == "character")
{
p <- p + geom_boxplot(mapping =
aes_string(x = input$var1,
y = input$var2))
}
else
{
p <- p + geom_point(mapping =
aes_string(x = input$var1,
y = input$var2))
}
return(p)
})
}
Just discovering shiny apps but this is driving me insane.......I have looked at numerous examples of server.R and ui.R code and cannot figure out what I am doing wrong. Apologies in advance if it's something very basic..........
Taking the iris dataset as an example, I want to plot one column against another, something simple using qplot or preferably ggplot
However, using qplot I get this:
and using ggplot2, I get the error:
I don't think I need the reactive function as I'm not subsetting the dataset, just extracting columns to plot.
server.R code
library(shiny)
library(shinyapps)
library(ggplot2)
shinyServer(function(input, output, session) {
output$text1 <- renderText({input$id1})
output$text2 <- renderText({input$select1})
output$plot1 <- renderPlot({
g <- qplot(Sepal.Length, input$select1, data = iris)
print(g)
})
})
or using ggplot function to replace the qplot call
g <- ggplot(iris, aes(x = Sepal.Length, y = input$select1))
g <- g + geom_line(col = "green", lwd =1) +
labs(x = "Date", y = "Ranking") +
theme_bw() + scale_y_reverse()
ui.R code
library(shiny)
library(shinyapps)
data(iris)
opts <- unique(colnames(iris))
opts <- opts[-1] ## want to keep Sepal.Length as the x values
shinyUI(pageWithSidebar(
headerPanel('test with iris database'),
sidebarPanel(
selectInput(inputId = "select1", label = "select",
choices = opts),
textInput(inputId = "id1", label = "Input Text", "")
),
mainPanel(
p('Output text1'),
textOutput('text1'),
textOutput('text2'),
plotOutput('plot1')
)
))
Change your aes statement to aes_string and make x a string. This should fix the problem.
g <- ggplot(iris, aes_string(x = "Sepal.Length", y = input$select1))
g <- g + geom_line(col = "green", lwd =1) +
labs(x = "Date", y = "Ranking") +
theme_bw() + scale_y_reverse()