I am having trouble creating a shiny app that creates a dynamic cross tab where one of the variables can be changed.
That is, I would like to create an app that creates a cross tab that shows the percentage of students that passed against each characteristic, as well as displaying this in a bar plot.
The bar plot is no problem. I cannot figure out how to vary the input into the cross tab.
The output$my_table section in the server object is where the problem is.
Any assistance would be greatly appreciated
library(shiny)
library(ggplot2)
students <- data.frame(Passed = c("Y","Y","Y","Y","Y","Y","N","N"), Gender = rep(c("Male","Female"), each = 4),
Subject = rep(c("Maths","Science"), times = 4),Campus =c(rep(c("Victoria"), times = 7), "NSW"))
ui <- fluidPage(
titlePanel("Percentage Passed by Characteristic"),
sidebarLayout(sidebarPanel(
selectInput(
"Characteristic",
"Student characteristic",
choices = colnames(students)[!colnames(students) %in% c("Passed")],
selected = colnames(students)[2]
)
),
mainPanel(
tabPanel("Plot",
fluidRow(
plotOutput("barplot"),
verbatimTextOutput("summary"))
),
tabPanel("Summary",
tableOutput("my_table"))
)
))
server <- function(input, output) {
output$barplot <- renderPlot({
var <- input$Characteristic
gg <-
ggplot(students, aes_string(x = var, fill= "Passed"))
gg <- gg + geom_bar(position = "Stack")
gg
})
output$my_table <- renderTable({
var <- input$Characteristic
prop.table(table(students$Passed, students$var),1)
})
}
# Create Shiny object
shinyApp(ui = ui, server = server)
The problem is that students$var refers to a column literally named "var", whereas you want the column named by the value of var: students[[var]].
This is addressed the question "access data frame column using variable", and answered in the last sentence of the winning answer. access data frame column using variable
I diagnosed the problem by running your code in an interactive R session, setting var to Gender, then running the prop.table(... line, which gives the error:
Error in table(students$Passed, students$var) :
all arguments must have the same length
The next problem you'll face is formatting the resulting prop.table, but that deserves another question.
Related
Not sure why my code shows all the countries' plots at the same time, I want to make it display only the country that's selected by the user. Does anyone know what went wrong with the code?
library(shiny)
require(readr)
countries <- read.csv("~/Desktop/share-deaths-suicide.csv")
# Define UI for application that draws a scatterplot
ui <- fluidPage(
# Application title
titlePanel("Country Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput("Entity",
"countries",
paste(countries$Entity),
selected = "China", multiple = FALSE)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("countryPlot")
)
)
)
# Define server logic required to draw a scatterplot
server <- function(input, output) {
output$countryPlot <- renderPlot({
country = input$Entity
plot(countries$Year, countries$`Deaths...Self.harm...Sex..Both...Age..All.Ages..Percent`, col=ifelse(countries$Entity==country, "red","black"),
main = "Sucide Rate of Countries", xlab = "Year", ylab = "Sucide rate",log="xy")
options(scipen=999)
})
}
# Run the application
shinyApp(ui = ui, server = server)
The issue is that you do not filter your data for the selected country. According to your code only the color is changed for the selected country.
To fix you issue you have to filter your data before passing it to plot. To this end you could add a reactive which filters the data. The filtered data could then be used via countries_filtered() where the parantheses are important. Additionally I have fixed an issue with your selectInput. Instead of passing the vector of entities use only the unique values for the choices argument.
As you provided no example data (to this end I would suggest to have a look at how to provide provide a minimal reproducible example) I use the gapminder dataset as example data:
library(shiny)
# Example data
library(gapminder)
countries <- gapminder
names(countries)[c(1, 3, 4)] <- c("Entity", "Year", "Deaths...Self.harm...Sex..Both...Age..All.Ages..Percent")
# Define UI for application that draws a scatterplot
ui <- fluidPage(
# Application title
titlePanel("Country Data"),
# Sidebar with a slider input for number of bins
sidebarLayout(
sidebarPanel(
selectInput("Entity",
"countries",
choices = unique(countries$Entity),
selected = "China", multiple = FALSE)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("countryPlot")
)
)
)
# Define server logic required to draw a scatterplot
server <- function(input, output) {
countries_filtered <- reactive({
req(input$Entity)
countries[countries$Entity == input$Entity, ]
})
output$countryPlot <- renderPlot({
country = input$Entity
plot(countries_filtered()$Year, countries_filtered()$`Deaths...Self.harm...Sex..Both...Age..All.Ages..Percent`,
col=ifelse(countries$Entity==country, "red","black"),
main = "Sucide Rate of Countries", xlab = "Year", ylab = "Sucide rate",log="xy")
options(scipen=999)
})
}
# Run the application
shinyApp(ui = ui, server = server)
#>
#> Listening on http://127.0.0.1:4061
1: You need to filter the dataset for the input country
And I will demonstrate this using ggplot:
output$countryPlot <- renderPlot({
countries %>%
filter(country == input$Entity) %>%
plot(aes(Year, countries$`Deaths...Self.harm...Sex..Both...Age..All.Ages..Percent`, color= Entity)) +
geom_point() +
labs(main = paste("Sucide Rate of", input$Entity), xlab = "Year", ylab = "Sucide rate") +
scale_y_log10() +
scale_x_log10() +
scale_fill_manual(values=c("red", "black"))
options(scipen=999)
})
I am not exactly sure why you wanted to color the points of the scatter plot based on "entity" as it seems that entity is the country input and the original plot would change the color of the points based on the user selection. In my above code, it would change the entire plot to only show the selected country, and changes the title based on the country selected as well.
Is there a way to link user input (x-axis, y-axis, colour etc) to the gganimate graph in R shiny? So that when the user selects a different input (x-axis, y-axis, colour, etc.) from the drop-down list. gganimate graph will be filled with different x-axis, y-axis, colour, etc. so that it can be changed accordingly?
The coding I tried as below. And there is error due to the variable name I saved in UI (xValue, yValue, colorValue etc which are putting in ggplot function) does not apply in the Serve...
The idea of UI code come from here: https://shiny.rstudio.com/articles/layout-guide.html
And it would display sth like this:
library(shiny)
library(shinythemes)
library(palmerpenguins)
library(gganimate)
library(dplyr)
library(tidyr)
library(ggplot2)
library(gapminder)
data(package = 'palmerpenguins')
ui <- fluidPage(
navbarPage(
"Animated penguins data",
tabPanel("Navbar 2",
##########
imageOutput('plot'),
hr(),
fluidRow(
column(3,
h4("Diamonds Explorer"),
sliderInput('sampleSize', 'Sample Size',
min=1, max=nrow(penguins), value=min(1000, nrow(penguins)),
step=500, round=0),
br(),
checkboxInput('jitter', 'Jitter'),
checkboxInput('smooth', 'Smooth')
),
column(4, offset = 1,
xValue -> selectInput('x', 'X', names(penguins)),
yValue -> selectInput('y', 'Y', names(penguins), names(penguins)[[2]]),
colorValue -> selectInput('color', 'Color', c('None', names(penguins)))
),
column(4,
rowValue -> selectInput('facet_row', 'Facet Row', c(None='.', names(penguins))),
columnValue -> selectInput('facet_col', 'Facet Column', c(None='.', names(penguins)))
)
)
#########
),
) # navbarPage
) # fluidPage
The idea of serve come from here: How to create and display an animated GIF in Shiny?
The server is sth. like this
# Define server function
server <- function(input, output) {
##########################################
output$plot <- renderImage({
# A temp file to save the output.
# This file will be removed later by renderImage
outfile <- tempfile(fileext='.gif')
# now make the animation
p = myPenguins %>%
ggplot(
aes(xValue, yValue, color = colorValue)) +
geom_point() +
#geom_line() +
facet_grid(rows = vars(rowValue), cols = vars(columnValue))+
theme_bw()+
#theme_minimal() +
transition_time(year)+
labs(title = "Year: {frame_time}")+
view_follow()#+
anim_save("outfile.gif", animate(p)) # New
# Return a list containing the filename
list(src = "outfile.gif",
contentType = 'image/gif')
}, deleteFile = TRUE)
################################################################
}
shinyApp(ui = ui, server = server)
Your code is still far from minimal and I don't have many of the packages you reference, but I think the following will illustrate the techniques that will allow you to do what you want. I've based my code on the diamonds dataset, which is part of ggplot2.
Your problem is due to the fact that Shiny input widgets (generally) return strings, whereas ggplot functions expect symbols as their argument. This is a feature of the tidyverse's use of non-standard evaluation (NSE).
As a result, the interface between Shiny and the tidyverse can be perplexing when you first come across it. One solution is to use the bang-bang operator (!!) and the sym function.
The following app displays a faceted scatter plot in which the user has complete control over the variables that
are plotted on the x axis
are plotted on the y-axis
define the colours of the plotted points
define the facet rows
define the facet columns
library(shiny)
library(tidyverse)
ui <- fluidPage(
selectInput("x", "X variable:", names(diamonds)),
selectInput("y", "Y variable", names(diamonds), selected="price"),
selectInput("colour", "Colour: ", names(diamonds), selected="color"),
selectInput("facetRows", "Facet rows: ", names(diamonds), selected="clarity"),
selectInput("facetCols", "Facet columns", names(diamonds), selected="cut"),
plotOutput("plot")
)
server <- function(input, output) {
output$plot <- renderPlot({
diamonds %>%
ggplot() +
geom_point(aes(x=!!sym(input$x), y=!!sym(input$y), colour=!!sym(input$colour))) +
facet_grid(rows=vars(!!sym(input$facetRows)), cols=vars(!!sym(input$facetCols)))
})
}
shinyApp(ui = ui, server = server)
Note that the diamonds dataset is quite large and a poor choice of variables for any of the five roles I mention above can lead to lengthy delays!
I think this provides an answer to your question, but I'm not entirely sure because of the many disparate features in your code (eg saving a GIF file, use of gganimate, reference to gapminder) that do not seem relevant to the question of using UI inputs in a call to renderPlot. If I haven't given you what you want, please refine your question and code so that they reference only the elements that are critical to the fundamental issue.
This post will help you construct a minimal reproducible example.
I am having two columns in my data frame, one is "all_pass" which contains numeric values and other is "st_name" which contains string values name of states
The requirement of the plot is , when user give input of the state it will show the plot of that particular state which contains all_pass numbers
Following is the code in which I am trying to plot, where the user will input the name of the state and as per the input of the state name, the graph will plot as per the all_pass as per the related pass scores to that particular state. Kindly help in the following code, will be of great help.
Code is as mentioned below :
library(ggplot2)
library(plotly)
library(dplyr)
library(shiny)
ui <- basicPage(
h1("Total bills passed by state delegation , 110th Congress"),
selectizeInput(inputId = "bins",label = "Choose State",
choices = list("AK","AL","AR","AS","AZ","CA","CO","CT","DC","DE","FL","GA","GU","HI","IA","ID","IL","IN","KS","KY","LA","MA","MD","ME","MI","MN","MO","MS","MT","NC","NE","ND","NH","NJ","NM","NV","NY","OH","OK","OR","PA","PR","RI","SC","SD","TN","TX","UT","VA") ,multiple = TRUE ,plotOutput("plot"))
)
server <- function(input, output) {
data <- reactive({
require(input$bins)
df <- df7 %>% filter(st_name %in% input$bins)
})
output$plot <- renderPlot({
ggplot(df(), aes(y= all_pass,x=st_name ))+geom_bar(stat = "sum")
})
}
shinyApp(ui = ui, server = server)
in the UI definition you have plotOutput("plot") as an argument to selectizeInput() instead of basicPage(). Reformatting your code (Ctrl+Shift+A) would have made that more visible.
You can simplify the server code, as the renderPlot() already creates a reactive dependence on input$bins.
You can use the object datasets::state.abb to get a vector of US state abbreviations. This is loaded automatically in every R session.
Please see some working code below. I am using some mock data for df as you did not provide any data in your question.
library(ggplot2)
library(plotly)
library(dplyr)
library(shiny)
ui <- basicPage(
h1("Total bills passed by state delegation, 110th Congress"),
selectizeInput(inputId = "bins",
label = "Choose State",
choices = state.abb,
multiple = TRUE),
plotOutput("plot")
)
server <- function(input, output) {
df <-
tibble(all_pass = sample(1:500, 350),
st_name = rep(state.abb, 7))
output$plot <- renderPlot({
req(input$bins)
df |>
filter(st_name %in% input$bins) |>
ggplot(aes(y = all_pass,x=st_name )) +
geom_bar(stat = "sum")
})
}
shinyApp(ui = ui, server = server)
i have the following shiny application:
Dataset:(https://www.kaggle.com/rush4ratio/video-game-sales-with-ratings)
library(shinythemes)
library(shiny)
library(ggplot2)
ui = navbarPage(theme = shinytheme("united"),"Video Games Dashboard",
tabPanel("Dashboard",
sidebarLayout(
sidebarPanel(
selectInput(inputId = "dataset",
label = "Choose a dataset:",
choices = colnames(data)),
),
mainPanel(
plotOutput(outputId = "ggPlot"),
plotOutput(outputId = "ggPlot2"),
)
)
),
tabPanel("Summary",
)
)
server <- function(input, output) {
output$ggPlot <- renderPlot({
ggplot ( data=data,aes(x=Global_Sales, y=input$dataset)) +
geom_bar(stat="identity" ,fill="steelblue") +
coord_flip() +
theme_minimal()
})
output$ggPlot2 <- renderPlot({
ggplot ( data=data,aes(x=Global_Sales, y=Platform)) +
geom_bar(stat="identity" ,fill="steelblue") +
theme_minimal()
})
}
shinyApp(ui = ui, server = server)
Which looks like this:
As you can see I want to do the same in the first plot("ggPlot") like in the second plot("ggPlot2") just that the first plot is reactive and you can select every column of the datatable to display it in the plot.
However, I get this message all the time:
Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
Does anybody know how to fix this? Is this approach even possible?
Thanks!
This warning appears when there's a single item on one of the two axes - see this shiny issue.
But your code does not produce the plot you expect: input$dataset is the name of a column of the data, hence it is a string, and then when you do aes(x = Global_Sales, y = input$dataset), the y argument of aes is not set to a variable of the data, it is set to a string. So you have a single item on the y-axis, hence the warning.
To set the arguments of aes to some variables of the data when you have the names of these variables, you can use aes_string:
aes_string(x = "Global_Sales", y = input$dataset)
I am trying to add graph for the output which i have generated using shiny. I am getting error for graph generation. Can someone please have a look and assist. The bar graph parameters are calculation based outputs generated from calculations.
server
output$graph<- renderPlotly({
plotly( x= c(as.numeric(input$contract), round(frateperton()), differencerate()),
y= c('Contract Rate', 'ZBC Rate', 'Difference'),
name = "Zero Based Rate Chart",
type = "bar")
})
UI
plotlyOutput("graph"),
First of all, two remarks on your post :
it is not reproducible, see here to learn what a reproducible example is and how to make one
clearly you haven't searched enough. Typing "r shiny plotly output" in any search engine gives several potential solutions (here for example).
To avoid duplicated posts, please consider these two points next time.
Now, here's the answer (using iris data since your example is not reproducible):
library(shiny)
library(plotly)
ui <- fluidPage(
selectInput("choice", "Choose", choices = names(iris), selected = NULL),
plotlyOutput("graph")
)
server <- function(input, output, session){
output$graph <- renderPlotly({
plot_ly(iris, x = ~get(input$choice), y = ~Sepal.Length, type = 'scatter', mode = 'markers')
})
}
shinyApp(ui, server)