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()
Related
I wasted hours to find out why my plot is automatically updating itself when I change inputs while it was supposed to wait for the Run button but it simply ignored that step and I ended up finally finding ggplot as the trouble maker!!! This is my minimal code:
library(ggplot2)
library(tidyverse)
varnames <- names(cars)
ui <- fluidPage(
sidebarLayout(
sidebarPanel(
fluidRow(
column(
width = 12,
# Variables Inputs:
varSelectInput("variables", "Select Input Variables", cars, multiple = TRUE),
selectizeInput("outvar", "Select Output Variable", choices = varnames, "speed", multiple = F),
# Run Button
actionButton(inputId = "run", label = "Run")
)
)
),
# Main panel for displaying outputs ----
mainPanel(
plotOutput("plot")
)
)
)
server <- function(input, output, session) {
df <- reactive({
cars %>% dplyr::select(!!!input$variables, input$outvar)
})
plt <- eventReactive(input$run, {
#Just creating lm formula
current_formula <- paste0(input$outvar, " ~ ", paste0(input$variables, collapse = " + "))
current_formula <- as.formula(current_formula)
#Fitting lm
fit <- lm(current_formula, data = df())
pred <- predict(fit, newdata = df())
#Plotting
ggplot(df(), aes(df()[, input$outvar], pred)) +
labs(x = "Observed", y = "Predicted") +
geom_point() +
theme_bw()
#plot(df()[, input$outvar], pred) #This one works fine!!!!
})
output$plot <- renderPlot({
plt()
})
}
# Run the application
shinyApp(ui = ui, server = server)
If you run this, you'll notice that ggplot doesn't care anymore about the Run button after the 1st run and it keeps updating as you change the inputs!! However, if you use the simple base plot function (which I put in a comment in the code) there wouldn't be any problems and that works just fine! Sadly I need ggplot in my app because base plot is ugly. I am seeing suggestion for using isolate() to solve this issue but I have no clue where isolate() should be put to fix my problem also it doesn't make sense to use isolate() when base plot function works fine without it and it's the ggplot that makes the problem. Any explanation would be appreciated.
The issue is that ggplot aesthetics are lazy evaluated. You really want to put symbols into the aes() rather that reactive data values. Change your plotting code to
ggplot(df(), aes(.data[[input$outvar]], pred)) +
labs(x = "Observed", y = "Predicted") +
geom_point() +
theme_bw()
With ggplot you use the .data pronoun to access the current data source rather than trigger the reactive df() object again.
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 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.
For a Shiny program I'm writing, I have input variables that contain a dash, commas and brackets. Spaces I can substitute out but the rest are needed since they are refering to chemical compounds and don't make sense without them. As expected, these characters make the Shiny app unable to find the desired variable; whilst variables with none of these characters work fine.
EDITED: The code below is a test Shiny app. With Chemical-X(a,b) the app returns "could not find function X". With Chemical.B the app returns "object Chemical.B not found" which is the desired result since the app sees the chemical as an object and not some function that doesn't exist.
library (shiny)
library (ggplot2)
dat <- as.data.frame(c("Chemical-X(a,b)", "Chemical.B"))
dat[,2] <- (c(6,3))
colnames(dat) <- c("Chemical", "Count")
ui <- fluidPage(
titlePanel("SE Test"),
sidebarLayout(
sidebarPanel(
selectInput(inputId = "varX",
label = "Chemical",
choices = dat[,1],
width = "200px"),
selectInput(inputId = "varY1",
label = "Count",
choices = dat[,2],
width = "200px")
),
mainPanel(
plotOutput("chemPlot")
)
)
)
server <- function(input, output){
output$chemPlot <- renderPlot({
plot.data <- ggplot(data = dat)
point <- plot.data + geom_point(
aes_string(x = input$varX, y = input$varY1))
plot(point)
})
}
shinyApp(ui = ui, server = server)
Is there a known way of doing this or will I need to come up with some viable work around? I have tried using backticks as suggested here but this hasn't worked.
Thanks, Matt
I have found that backticks and aes_string usually works for me.
library("ggplot2")
my_dodgy_var <- "name with~special character"
mtcars[[my_dodgy_var]] <- mtcars$cyl
ggplot(mtcars, aes_string(x=paste0("`", my_dodgy_var, "`"), y="mpg")) +
geom_point()
I often use a helper function paste_aes to do this, eg:
paste_aes <- function(x) paste0("`", x, "`")
I've fixed it now by calling as.name the Shiny input$ variable. For the example above it would look like this.
server <- function(input, output){
output$chemPlot <- renderPlot({
plot.data <- ggplot(data = dat)
point <- plot.data + geom_point(
aes_string(x = as.name(input$varX), y = as.name(input$varY1)))
plot(point)
This appears to work now as intended. Thank you aocall for your efforts.
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)