use R Shiny inputs to divide column for ggplot axis - r

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

Related

Interactive Bar Chart Using Shiny - Graph changes based on selected columns

I am teaching myself r and shiny and trying to make an interactive bar chart where the user can change the chart based on columns. I keep getting errors with this code. Any help would be appreciated! My data has four columns: v, one, two, three. The first column is characters and the last three are numbers. I want to change the bar chart based on the y axis (columns: one, two and three). Right now, the error I am getting is: missing value where TRUE/FALSE needed.
library(shiny)
library(readr)
library(ggplot2)
data <- read.csv('scoring.csv')
data$v <- as.character(data$v)
ui <- fluidPage(
titlePanel("Scoring"),
sidebarPanel(
selectInput(inputId = "scoring", label = "Select a score:", c("Scoring Method 1", "Scoring Method 2", "Scoring Method 3"))),
mainPanel(
plotOutput(outputId = "bar")
)
)
#browser()
server <- function(input, output) {
new_data <- reactive({
selected_score = as.numeric(input$"scoring")
if (selected_score == "Scoring Method 1"){(data[data$one])}
if (selected_score == "Scoring Method 2"){(data[data$two])}
if (selected_score == "Scoring Method 3"){(data[data$three])}
})
#browser()
output$bar <- renderPlot({
newdata <- new_data()
p <- ggplot(newdata, aes(x=reorder(v, -selected_score), selected_score, y = selected_score, fill=v)) +
geom_bar(stat = 'identity', fill="darkblue") +
theme_minimal() +
ggtitle("Sports")
barplot(p, height = 400, width = 200)
})
}
Run the application
shinyApp(ui = ui, server = server)
You have a few errors in your code. In the server part, please use input$scoring, instead of input$"scoring".
First, in ui selectInput could be defined as
selectInput(inputId = "scoring", label = "Select a score:", c("Scoring Method 1"="one",
"Scoring Method 2"="two",
"Scoring Method 3"="three")))
Second, your reactive dataframe new_data() could be defined as shown below:
new_data <- reactive({
d <- data %>% mutate(selected_score = input$scoring)
d
})
Third, ggplot could be defined as
output$bar <- renderPlot({
newdata <- new_data()
p <- ggplot(newdata, aes(x=v, y = newdata[[as.name(selected_score)]], fill=v)) +
geom_bar(stat = 'identity', position = "dodge", fill="blue") +
theme_bw() +
#scale_fill_manual(values=c("blue", "green", "red")) +
scale_y_continuous(limits=c(0,10)) +
ggtitle("Sports")
p
})
Please note that you had an extra selected_score variable within aes. My suggestion would be to play with it to reorder x, and review some online or youtube videos on R Shiny.

Displaying only those x values selected by the user

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()
)}
}

R/Shiny: Change plot ONLY after action button has been clicked

I am setting up a small shiny app where I do not want the plot to change unless the action button is clicked. In the example below, when I first run the app, there is no plot until I click the action button. However, if I then change my menu option in the drop-down from Histogram to Scatter, the scatter plot is automatically displayed even though the value for input$show_plot has not changed because the action button has not been clicked.
Is there a way that I can change my menu selection from Histogram to Scatter, but NOT have the plot change until I click the action button? I've read through several different posts and articles and can't seem to get this worked out.
Thanks for any input!
ui.R
library(shiny)
fluidPage(
tabsetPanel(
tabPanel("Main",
headerPanel(""),
sidebarPanel(
selectInput('plot_type', 'Select plot type', c('Histogram','Scatter'), width = "250px"),
actionButton('show_plot',"Plot", width = "125px"),
width = 2
),
mainPanel(
conditionalPanel(
"input.plot_type == 'Histogram'",
plotOutput('plot_histogram')
),
conditionalPanel(
"input.plot_type == 'Scatter'",
plotOutput('plot_scatter')
)
))
)
)
server.R
library(shiny)
library(ggplot2)
set.seed(10)
function(input, output, session) {
### GENERATE SOME DATA ###
source_data <- reactive({
mydata1 = as.data.frame(rnorm(n = 100))
mydata2 = as.data.frame(rnorm(n = 100))
mydata = cbind(mydata1, mydata2)
colnames(mydata) <- c("value1","value2")
return(mydata)
})
# get a subset of the data for the histogram
hist_data <- reactive({
data_sub = as.data.frame(source_data()[sample(1:nrow(source_data()), 75), "value1"])
colnames(data_sub) <- "value1"
return(data_sub)
})
# get a subset of the data for the scatter plot
scatter_data <- reactive({
data_sub = as.data.frame(source_data()[sample(1:nrow(source_data()), 75),])
return(data_sub)
})
### MAKE SOME PLOTS ###
observeEvent(input$show_plot,{
output$plot_histogram <- renderPlot({
isolate({
plot_data = hist_data()
print(head(plot_data))
p = ggplot(plot_data, aes(x = value1, y = ..count..)) + geom_histogram()
return(p)
})
})
})
observeEvent(input$show_plot,{
output$plot_scatter <- renderPlot({
isolate({
plot_data = scatter_data()
print(head(plot_data))
p = ggplot(plot_data, aes(x = value1, y = value2)) + geom_point()
return(p)
})
})
})
}
Based on your desired behavior I don't see a need for actionButton() at all. If you want to change plots based on user input then the combo of selectinput() and conditionPanel() already does that for you.
On another note, it is not good practice to have output bindings inside any reactives. Here's an improved version of your server code. I think you are good enough to see notice the changes but comment if you have any questions. -
function(input, output, session) {
### GENERATE SOME DATA ###
source_data <- data.frame(value1 = rnorm(n = 100), value2 = rnorm(n = 100))
# get a subset of the data for the histogram
hist_data <- reactive({
# reactive is not needed if no user input is used for creating this data
source_data[sample(1:nrow(source_data), 75), "value1", drop = F]
})
# get a subset of the data for the histogram
scatter_data <- reactive({
# reactive is not needed if no user input is used for creating this data
source_data[sample(1:nrow(source_data), 75), , drop = F]
})
### MAKE SOME PLOTS ###
output$plot_histogram <- renderPlot({
req(hist_data())
print(head(hist_data()))
p = ggplot(hist_data(), aes(x = value1, y = ..count..)) + geom_histogram()
return(p)
})
output$plot_scatter <- renderPlot({
req(scatter_data())
print(head(scatter_data()))
p = ggplot(scatter_data(), aes(x = value1, y = value2)) + geom_point()
return(p)
})
}

Unable to plot stacked barplot using R Shiny

I am new to R Shiny. Actually i have drawn Stacked Barplot using ggplot in my
R code. I want to draw the same using shiny. Below is my R code:
ggplot(data = df, aes(x = OutPut, y = Group, fill = Group)) +
geom_bar(stat = "identity") +
facet_grid(~ Environment)
In my R code it is giving correct results.But i am trying to draw in shiny. Below is my shiny R code.
ui <- fluidPage(theme = shinytheme("lumen"),
titlePanel("Data Analysis"),
selectInput("variable", "Variable:", c("OutPut", "Member", "Levels")),
mainPanel(plotOutput("plot")))
# Define server function
server <- function(input, output){
x = ggplot(data = df, aes(x = variable.names(), y = Group, fill = Group)) +
geom_bar(stat = "identity") +
facet_grid(~ Environment)
plot(x)
}
# Create Shiny object
shinyApp(ui = ui, server = server)
It is throwing an error,here i have created a dropdown box where all the variables have been stored. So when i select one variable, it should plot the Stacked barplot. Could anyone please help me.
Like it was mentioned in the comments, you need to use the rendering functions and actually assign them to the output to get the outputs you need.
I believe an example of using plots in rshiny would help, since it wouldn't make sense to have it in the comments, here it is:
library(shiny)
library(ggplot2)
ui <- fluidPage(titlePanel("Fast Example with mtcars"),
# inputs
selectInput("x", "Choose x:", choices = names(mtcars), selected = 'mpg'),
selectInput("y", "Choose y:", choices = names(mtcars), selected = 'hp'),
selectInput("fill", "Choose fill:", choices = names(mtcars), selected = 'carb'),
mainPanel(
#outputs
h2("Chosen variables are:"),
h4(textOutput("vars")),
plotOutput("plot")))
server <- function(input, output) {
df <- mtcars
# here's how you would use the rendering functions
# notice that I used aes_string
output$plot <- renderPlot({
ggplot(data=df,
aes_string(x= input$x, y= input$y, fill=input$fill)) +
geom_point()
})
output$vars <- renderText(paste0('x: ', input$x, " , ",
'y: ', input$y, " , ",
'fill: ', input$fill))
}
shinyApp(ui = ui, server = server)
The Rshiny tutorial is pretty helpful, you can take a look at it here https://shiny.rstudio.com/tutorial/

R Shiny ggplot bar and line charts with dynamic variable selection and y axis to be percentages

I am learning Shiny and wanted help on a app that I am creating. I am creating an app that will take dynamic inputs from the user and should generate bar and line charts. I managed to create the bar chart but it is generating incorrect result.
What I am looking for is variable selected in row should be my x-axis and y-axis should be percentage. scale to be 100%. column variable should be the variable for comparison and for that I am using position = "dodge". My data is big and I have created a sample data to depict the situation. Since actual data is in data.table format I am storing the sample data as data.table. Since I am not sure how I can include this data which is not in a file format, I create it first so that it is in R environment and then run the app -
Location <- sample(1:5,100,replace = T)
Brand <- sample(1:3,100,replace = T)
Year <- rep(c("Year 2014","Year 2015"),50)
Q1 <- sample(1:5,100,replace = T)
Q2 <- sample(1:5,100,replace = T)
mydata <- as.data.table(cbind(Location,Brand,Year,Q1,Q2))
Below is the Shiny code that I am using -
library("shiny")
library("ggplot2")
library("scales")
library("data.table")
library("plotly")
ui <- shinyUI(fluidPage(
sidebarPanel(
fluidRow(
column(10,
div(style = "font-size: 13px;", selectInput("rowvar", label = "Select Row Variable", ''))
),
tags$br(),
tags$br(),
column(10,
div(style = "font-size: 13px;", selectInput("columnvar", "Select Column Variable", ''))
))
),
tabPanel("First Page"),
mainPanel(tabsetPanel(id='charts',
tabPanel("charts",tags$b(tags$br("Graphical Output" )),tags$br(),plotlyOutput("plot1"))
)
)
))
server <- shinyServer(function(input, output,session){
updateTabsetPanel(session = session
,inputId = 'myTabs')
observe({
updateSelectInput(session, "rowvar", choices = (as.character(colnames(mydata))),selected = "mpg")
})
observe({
updateSelectInput(session, "columnvar", choices = (as.character(colnames(mydata))),selected = "cyl")
})
output$plot1 <- renderPlotly({
validate(need(input$rowvar,''),
need(input$columnvar,''))
ggplot(mydata, aes(x= get(input$rowvar))) +
geom_bar(aes(y = ..prop.., fill = get(input$columnvar)), position = "dodge", stat="count") +
geom_text(aes( label = scales::percent(..prop..),
y= ..prop.. ), stat= "count", vjust = -.5) +
labs(y = "Percent", fill=input$rowvar) +
scale_y_continuous(labels=percent,limits = c(0,1))
})
})
shinyApp(ui = ui, server = server)
If you see the problem is -
All bars are 100%. Proportions are not getting calculated properly. Not sure where I am going wrong.
If I try to use the group parameter it gives me error saying "input" variable not found. I tried giving group as group = get(input$columnvar)
I believe I need to restructure my data for line chart. Can you help with how I can dynamically restructure the data.table and then re-use for the line chart. How can I generate the same bar chart as a line chart.
I am using renderplotly so that I use the features of plotly to have the percentages displayed with the mouse movement / zoom etc. However I can see input$variable on mouse movement. How can I get rid of it and have proper names.
Have tried to detail out the situation. Do suggest some solution.
Thank you!!
To properly group variables for plotting, geom_bar requires that the x values be numeric and the fill values be factors or that the argument group be used to explicitly specify grouping variables. However, plotly throws an error when group is used. The approach below converts x variables to integer and fill variables to factor so that they are properly grouped. This retains the use of geom_bar to calculate the percentages.
First, however, I wonder if mydata is specified correctly. Given that the data is a mix of character and integer, cbind(Location, Brand, Year, Q1, Q2) gives a character matrix which is then converted to a data.table where all variables are character mode. In the code below, I've defined mydata directly as a data.table but have converted Q1 to character mode so that mydata contains a mix of character and numeric.
The approach used below is to create a new data frame, plotdata, containing the x and fill data. The x data is converted to numeric, if necessary, by first making it a factor variable and then using unclass to get the factor integer codes. The fill data converted to a factor. plotdata is then used generate the ggplot plot which is then displayed using plotly. The code includes a couple of other modifications to improve the appearance of the chart.
EDIT
The code below has been updated to show the name of the row variable beneath it's bar. Also the percentage and count for each bar are only shown when the mouse pointer hovers above the bar.
library("shiny")
library("ggplot2")
library("scales")
library(plotly)
library(data.table)
Location <- sample(1:5,100,replace = T)
Brand <- sample(1:3,100,replace = T)
Year <- rep(c("Year 2014","Year 2015"),50)
Q1 <- sample(1:5,100,replace = T)
Q2 <- sample(1:5,100,replace = T)
Q3 <- sample(seq(1,3,.5), 100, replace=T)
mydata <- data.table(Location,Brand,Year,Q1,Q2, Q3)
#
# convert Q1 to character for demonstation purposes
#
mydata$Q1 <- as.character(mydata$Q1)
ui <- shinyUI(fluidPage(
sidebarPanel(
fluidRow(
column(10,
div(style = "font-size: 13px;", selectInput("rowvar", label = "Select Row Variable",
choices=colnames(mydata)))),
tags$br(),
tags$br(),
column(10,
div(style = "font-size: 13px;", selectInput("columnvar", label="Select Column Variable",
choices=colnames(mydata))))
)
),
tabPanel("First Page"),
mainPanel(tabsetPanel(id='charts',
tabPanel("charts",tags$b(tags$br("Graphical Output" )),tags$br(),plotlyOutput("plot1"))
)
)
))
server <- shinyServer(function(input, output,session){
updateTabsetPanel(session = session
,inputId = 'myTabs')
observe({
updateSelectInput(session, "rowvar", choices = colnames(mydata), selected=colnames(mydata)[1])
})
observe({
updateSelectInput(session, "columnvar", choices = colnames(mydata), selected=colnames(mydata)[2])
})
output$plot1 <- renderPlotly({
#
# create data frame for plotting containing x variables as integer and fill variables as factors
#
if(is.numeric(get(input$rowvar))) {
rowvar_brks <- sort(unique(get(input$rowvar)))
rowvar_lbls <- as.character(rowvar_brks)
plotdata <- data.frame(get(input$rowvar), factor(get(input$columnvar)) )
}
else {
rowvar_factors <- factor(get(input$rowvar))
rowvar_brks <- 1:nlevels(rowvar_factors)
rowvar_lbls <- levels(rowvar_factors)
plotdata <- data.frame(unclass(rowvar_factors), factor(get(input$columnvar)) )
}
colnames(plotdata) <- c(input$rowvar, input$columnvar)
validate(need(input$rowvar,''),
need(input$columnvar,''))
col_width <- .85*mean(diff(rowvar_brks))
sp <- ggplot(plotdata, aes_(x = as.name(input$rowvar), fill = as.name(input$columnvar))) +
geom_bar( aes(y= ..prop..), stat="count", position=position_dodge(width=col_width)) +
geom_text(aes( label = paste(scales::percent(..prop..),"<br>", "count:",..count..,"<br>"), y= ..prop.. + .01),
stat= "count", position=position_dodge(width=col_width), size=3, alpha=0) +
labs(x= input$rowvar, y = "Percent", fill=input$columnvar) +
scale_y_continuous(labels=percent) +
scale_x_continuous(breaks=rowvar_brks, labels=rowvar_lbls)
ggplotly(sp, tooltip="none")
})
})
shinyApp(ui = ui, server = server)

Resources