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)
Related
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 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.
I have tried to plot the graph separately using ggplot (outside the shiny app) and it plots well so I know the problem is not with my ggplot code but with how the inputs in the shiny app are entered into the renderplot({}) section. The inputs are the axes.
Code:
library(ggplot2)
library(shiny)
data1 <- mtcars
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
selectInput(
inputId = "xaxis",
label = "Choose a Variable for the X-axis of the First Graph",
choices = colnames(data1)
),
selectInput(
inputId = "yaxis",
label = "Choose a Variable for the Y-axis of the First Graph",
choices = colnames(data1)
)
),
mainPanel(
plotOutput(outputId = "scatterplot"))
)
)
server <- function(input, output) {
output$scatterplot <- renderPlot({
req(input$xaxis)
req(input$yaxis)
ggplot(data1, aes(x = input$xaxis, y = input$yaxis))+geom_point()
})}
shinyApp(ui = ui, server = server)
Solution
You are passing a string to your aes, which does not work. You should try
server <- function(input, output) {
output$scatterplot <- renderPlot({
req(input$xaxis)
req(input$yaxis)
gggplot(data1, aes_string(x = paste0("`", input$xaxis, "`"),
y = paste0("`", input$yaxis, "`"))) + geom_point()
})
}
Explanation
aes expects the bare column name like in ggplot(mtcars, aes(am, vs)) + geom_point(). Note that we do not use quotatation marks " for am or vs (i.e. we are passing variable names and not strings). On the other hand input$xaxis returns a string. Thus, you have to use aes_string which is meant for working with strings rather than column names.
Update
Added backtricks to deal with non standard names.
I'm trying to add a feature where the user can look at a plot of all time stamps from several patients of a certain variable, select a point and see which patient that point belongs to, as well as all other information about the patient at that time stamp. My data is reactive because the SQL Query that fetches it requires user input. I'm trying to use click in plotOutput and nearPoints in the server, and the clicker will show up when hovered over the plot, although if I try to click on a point, nothing will happen (the data display will remain null). Here is what I have:
#ui.R
library(shiny)
library(ggplot2)
shinyUI(navbarPage("Choose Page",
tabPanel("Page 1",
#sidebar
sidebarLayout(
sidebarPanel(
*unrelated tab*
)
)
),
tabPanel("Overall Metrics",
sidebarLayout(
sidebarPanel(
h3("Metrics Across All Patients"),
selectInput("selecty1",
label = "Choose a variable to display on the y-axis:",
choices = list('Var1', 'Var2', 'Var3', 'Var4')),
dateRangeInput("dates1", label= "Date Range:"),
submitButton("Create Graph"),
),
mainPanel(
plotOutput('plot1', click = "plotClick"),
verbatimTextOutput("click_info")
)
)
)
)
)
#server.R
library(shiny)
require(RODBC)
library(ggplot2)
library(quantmod)
library(reshape)
shinyServer(function(input, output) {
chan2 <- odbcConnect('date_base', uid='username')
queryString2 <- reactive({sprintf("**SQL Query**",input$dates1[1],input$dates1[2])})
overallData <- reactive({sqlQuery(chan2, queryString2())})
output$heartplot1 <- renderPlot({
ggplot(overallData(), aes_string(x = "Time_Stamp", y = input$selecty1)) + geom_point(size=2) + geom_line(aes(colour = factor(PatientNum))) + theme_bw() + stat_smooth(method="lm",se=FALSE,size=1)
})
output$click_info <- renderPrint({
nearPoints(overallData(), input$plotClick, addDist = FALSE)
})
})
All demos I find of nearPoints use typical data tables, how can I make this work with reactive data, or is that not the problem here?
I'm trying to allow the user to select which column of data (selecty) they would like to make a plot of. Everything else in my app works except for this part. Here are the relevant portions of my code:
#ui.R
library(shiny)
library(ggplot2)
shinyUI(fluidPage(h1("Title 1"),
# Sidebar
sidebarLayout(
sidebarPanel(
h3("Title 2"),
selectInput("pnum",
label = "Select the patient number",
choices = unique(pnums), selected = pnums[1]),
selectInput("selecty",
label = "Choose a variable to display on the y-axis",
choices = list('Var1', 'Var2', 'Var3', 'Var4')),
dateRangeInput("dates", label= "Date Range"),
submitButton("Create Graph")
),
# Show a plot
mainPanel(
plotOutput('makeplot')
)
)
))
#server.R
#relevant portion only - ggplot
library(shiny)
require(RODBC)
library(ggplot2)
library(quantmod)
library(reshape)
shinyServer(function(input, output) {
output$makeplot <- renderPlot({
p <- ggplot(pdata(), aes(x = Time_Stamp, y = input$yselect)) + geom_point()
print(p)
})
})
The data is brought from an online database and is a reactive function. My main issue is that in the user select for the column, it has to be in single quotes, although I would like to transfer it over to the ggplot function without the quotes so it acts as the column name. I've also tried to make a switch statement within the 'y = ' but I get the same error.
First, in your ggplot call, you should have y = input$selectyto be consistent with your naming in ui.R.
Then, if I understood correctly, you should take a look at the aes_string function in ggplot because aes uses non-standard evaluation which allows you to specify variable names directly and not as characters. Here, input$yselect is passed as a character so you need to replace in server.R :
p <- ggplot(pdata(), aes(x = Time_Stamp, y = input$yselect)) + geom_point()
with
p <- ggplot(pdata(), aes_string(x = "Time_Stamp", y = input$selecty)) + geom_point()