New to R, Not sure why my graph wouldn't be populating - r

I am a newbie to R, it's definitely been a learning curve and I am still bad at it. I can't really solve this issue myself as I don't really know what I am doing wrong.
library(shiny)
library(dplyr)
library(readxl)
#UI
ui <- fluidPage(
#Title
titlePanel("Testing Shiny"),
#Sidebar Layout
sidebarLayout(
# Sidebar panel
sidebarPanel(
#Input
selectInput("typedata",
label = "What do you want to see?",
list("Count of Job Reqs",
"Candidates")),
selectInput("Work Location", label = "Location", choices = unique(exceldata$"Work Location")),
),
#Main Panel
mainPanel(
#Output
textOutput("selected_typedata"),
textOutput("totalreq"),
plotOutput("plot")
)
)
)
#Server
server <- function(input, output) {
output$selected_typedata <- renderText({
paste("You wanted to see", input$typedata)
})
output$plot <- renderPlot({
ggplot(data=exceldata, aes(x=exceldata$`Application Date`,
y=exceldata$`Candidate ID`, fill=c('steelblue'))) +
geom_bar(stat='Identity', width=0.8)
})
}
#Shiny app
shinyApp(ui = ui, server = server)
What it's doing is not actually graphing anything. I don't know why, it draws the x and y, but not the actual bars. What I am trying to accomplish here is a basic bar graph showing the count of candidate IDs that applied during their application dates.
If someone could point out what I could possibly be doing wrong, I would greatly appreciate it. I tried using (count(exceldata$"Application Date')), but it gives me an error "no applicable method for 'tbl_vars' applied to an object of class "c('double', 'numeric')".
I tried reading documentation, and it just works fine for others. My data comes from a table loaded as a function using read_excel.

Related

Forcing render order in R Shiny

I'm relatively new to R Shiny and reactive programming. From my understanding (and this tutorial), it seems like you are not supposed to tell Shiny "when" to do things (i.e. to enforce execution order) as it will figure that out itself. However, often I find myself wanting plots or other UI to render sequentially. Is there a good way to do this?
I've made up a minimal example below. I want to render header before plot, as plot requires a time-consuming computation.
library(shiny)
ui <- fluidPage(
tags$h1("My app"),
uiOutput("header"),
plotOutput("plot")
)
server <- function(input, output) {
output$header <- renderUI({
tagList(tags$h2("Section header"),
tags$p("Some information relevant to the plot below..."))
})
output$plot <- renderPlot({
# hypothetical expensive computation
Sys.sleep(2)
# hypothetical plot
hist(rnorm(20))
})
}
shinyApp(ui = ui, server = server)
Here I could obviously replace uiOutput("header") in ui with its definition in server and that solves the problem; however, in practice I want header to be dynamic. A hacky solution I found was to include a hidden input inside header and then use req() inside plot. This is kind of like adding an action button that automatically clicks upon load.
server <- function(input, output) {
output$header <- renderUI({
tagList(tags$h2("Section header"),
tags$p("Some information relevant to the plot below..."),
div(style = "display:none", textInput(inputId = "hidden", label = "", value = "x")))
})
output$plot <- renderPlot({
req(input$hidden)
...
})
}
However, if I want to repeat this in multiple situations or if I want to force a chain of more than two outputs to render sequentially, then this seems tedious. Can anyone suggest a more elegant solution?
As your example code includes a "time-consuming computation" I guess in the end you don't really want to control the render order, instead you want to avoid long running functions to block the execution of other parts of your code (XY problem).
By default, R is single threaded, therefore we'll need child processes to solve this issue.
In shiny you can use library(future) + library (promises) for this. However, using asynchronous processes to unblock the elements within a shiny session requires us to "hide" the promise - read more about it here.
Below please find an async version of your example:
library(shiny)
library(promises)
library(future)
plan(multisession)
ui <- fluidPage(
tags$h1("My app"),
uiOutput("header"),
plotOutput("plot")
)
server <- function(input, output) {
output$header <- renderUI({
tagList(tags$h2("Section header"),
tags$p("Some information relevant to the plot below..."))
})
data <- reactiveVal()
observe({
future_promise({
# hypothetical expensive computation
Sys.sleep(2)
# hypothetical plot data
rnorm(20)
}, seed=TRUE) %...>% data()
return(NULL) # "hide" the future_promise
})
output$plot <- renderPlot({
req(data(), cancelOutput = TRUE)
hist(data())
})
}
shinyApp(ui = ui, server = server)
In Shiny, for a given session, no outputs are sent back to the client, until all outputs are ready : the text render function isn't sent until the plot render function completes, see shiny flush cycle.
A workaround is to skip plot rendering using a reactiveVal so that the text gets displayed in a first flush cycle, and then to use invalidateLater() to launch a new flush cycle to run the longer plot rendering.
library(shiny)
ui <- fluidPage(
tags$h1("My app"),
uiOutput("header"),
plotOutput("plot")
)
server <- function(input, output,session) {
skipPlot <- reactiveVal(1)
output$header <- renderUI({
tagList(tags$h2("Section header"),
tags$p("Some information relevant to the plot below..."))
})
output$plot <- renderPlot({
if (isolate(skipPlot()==1)) {
# skip first reactive sequence
skipPlot(0)
# launch next reactive sequence
invalidateLater(1,session)
} else {
# hypothetical expensive computation
Sys.sleep(2)
# hypothetical plot
hist(rnorm(20))
}
})
}
shinyApp(ui = ui, server = server)

Shiny app: Can't plot stock chart based on user input

I am trying to plot a stock chart using quantmod in a shiny app but I get the following error: input$stockInput download failed after two attempts. Error message: HTTP error 404. Any help is appreciated.
Server:
library(quantmod)
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
price <- getSymbols('input$stockInput',from='2017-01-01')
plot(price)
})})
UI:
library(shiny)
shinyUI(fluidPage(
titlePanel("Stock Chart"),
sidebarLayout(
sidebarPanel(
#This is a dropdown to select the stock
selectInput("stockInput",
"Pick your stock:",
c("AMZN","FB","GOOG","NVDA","AAPL"),
"AMZN"),selected = "GOOG"),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
))))
Thank you.
Your code requires a few changes. First when you are accessing a shiny UI object in server.R you should use it as an object not as a quoted character
price <- getSymbols(input$stockInput,from='2017-01-01')
And the function getSymbols without a value set to the argument (auto.assign = F) creates a new xts object in the stock name whose data is requested and so in the below code I've used it with setting auto.assign = F so it becomes easier to access the object price for plotting. Otherwise, you might have to fetch the value inside price using get() and then plot them as I've commented.
server.R
library(quantmod)
shinyServer(function(input, output) {
output$distPlot <- renderPlot({
price <- getSymbols(input$stockInput,from='2017-01-01', auto.assign = F)
#plot(get(price), main = price) #this is used when auto.assign is not set by default which is TRUE
plot(price, main = input$stockInput) # this is when the xts object is stored in the name price itself
})})
ui.R
library(shiny)
shinyUI(fluidPage(
titlePanel("Stock Chart"),
sidebarLayout(
sidebarPanel(
#This is a dropdown to select the stock
selectInput("stockInput",
"Pick your stock:",
c("AMZN","FB","GOOG","NVDA","AAPL"),
"AMZN"),selected = "GOOG"),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
))))
Hope it clarifies!

r shiny: Creating widgets in ui.R vs. renderUI + uiOutput

I have a question that falls more into a "best practice" type of inquiry. When using shiny package in r, is it better to create all widgets on the server side using renderUI and then pushing those to the ui via uiOutput? Or, when possible, should all widgets be created on the ui side?
For instance, the two apps below do the same thing but in the second one, I create the sliderInput on the server side and then push that to the ui rather than creating it in the ui side. (Note, this code is pulled from the Hello Shiny page on R Studio)
App 1 - "Standard Approach" creating widget in ui
#ui.R
# Define UI for application that plots random distributions
library(shiny)
ui1 <- shinyUI(fluidPage(
# Application title
titlePanel("Hello Shiny!"),
# Sidebar with a slider input for number of observations
sidebarLayout(
sidebarPanel(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 500)
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
#server.R
# Define server logic required to generate and plot a random distribution
library(shiny)
server1 <- (function(input, output) {
output$distPlot <- renderPlot({
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist)
})
})
runApp(shinyApp(ui = ui1, server = server1))
App 2 - Alternative Approach - Creating Widget on server side
#ui.R
# Define UI for application that plots random distributions
library(shiny)
ui2 <- shinyUI(fluidPage(
# Application title
titlePanel("Hello Shiny!"),
# slider comes from the si object created in server.R
sidebarLayout(
sidebarPanel(
uiOutput("si")
),
# Show a plot of the generated distribution
mainPanel(
plotOutput("distPlot")
)
)
))
#server.R
# Define server logic required to generate and plot a random distribution
library(shiny)
server2 <- (function(input, output) {
#create slider with renderUI
output$si <- renderUI(
sliderInput("obs",
"Number of observations:",
min = 1,
max = 1000,
value = 500)
)
output$distPlot <- renderPlot({
# generate an rnorm distribution and plot it
dist <- rnorm(input$obs)
hist(dist)
})
})
runApp(shinyApp(ui = ui2, server = server2))
To me, the second approach is more generalizable so it should win. However, I am no expert and I rarely see this approach being used unless there is a specific reason why you need the widgets to be responsive in some way. The ways in which I have required responsiveness include:
There is data loaded on the server side which ends up feeding the widget choices so it is better to only load the data one time on the server side and create the widgets there, rather than load it on the server and ui side.
We need to turn off/on widgets and/or allow them to react to other user input
Since the second approach I've presented can handle the above two options, it makes sense to me that it should be used in all cases, even when there is no real need to create the widget on the server side. I notice that when using the second approach, there is a delay, sometimes accompanied by warnings/errors prior to the widgets being loaded. That is the only downside I've noticed about the approach.
Is one of these approaches considered a "best practice?"
Thanks.

R shiny, subscript out of bounds

I'm working with simple Shiny app in R, but I face this error in the app:
subscript out of bounds
The idea is to have a sidebar panel where you can choose vocal or consonant, and a barplot that visualize some letters with some numbers, clearly, choosing a vocal,vocals are with values, and so on with the consonant.
Here my code
First, I create the data:
x1<-c(1,2,6,3,8)
y1<-c('a','b','c','d','e')
z1<-c('V','C','C','C','V')
df<-data.frame(x1,y1,z1)
data.m <- melt(df, id=c(2:3), measure=c(1))
df2<-cast(data.m , z1 ~ y1)
df3<-as.matrix(df2)
Here the server code:
##server
function(input, output) {
output$Plot <- renderPlot({
library(reshape)
barplot(df3[,input$letters])
})
}
and here the ui part
##ui
fluidPage(
titlePanel("letters"),
sidebarLayout(
sidebarPanel(
selectInput("letters", "Letters",
choices=rownames(df3)),
hr(),
helpText("Types of letters")
),
mainPanel(
plotOutput("Plot")
)
)
)
Well the error is the one in the title. Could you help me?
Furthermore, is there any way to put the data into the Shiny app to have them loaded when you start the app?
Thanks a lot in advance

R/shiny: render elements of plots only when needed in shiny apps

I am currently writing a shiny application. I want to decrease the rendering time of plots (because it takes a long time to initialise a plot). Let's say I want to render a plot dynamically, e.g.
plot(x=1:10)
(plot will not be the function which I will use in the shiny app.)
Now I want to divide the plotting into several parts, here:
plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
points(x=1:10)
where plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10)) will take a very long time in the shiny app to render and points(x=1:10) will take a short time. I need a procedure which will execute plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10)) only when loading the app for the first time and then the plot will be build bottom-up (add points, lines, etc. to the plot). Has anybody an idea how to write this into an app? Problem here is that the function I will use in the shiny app to plot will not return anything. The plotting function is based on the base graphics system (not on ggplot2, not on lattice).
Here's a minimal working example for such an app:
library(shiny)
shinyAPP <- function() {
ui <- fluidPage(
sidebarPanel(),
mainPanel(
plotOutput("plotPoints"))
)
server <- function(input, output, session) {
output$plotPoints <- renderPlot(
plot(x=1:10)
## this needs to be replaced with:
##plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
##points(x=1:10)
)
}
app <- list(ui = ui, server = server)
runApp(app)
}
shinyAPP()
Thank you very much!
So maybe try grDevices, like here:
server.R:
library("shiny")
library("grDevices")
data(iris)
plot(x=NA, y=NA, xlim=c(0,10), ylim=c(0,10))
p <- recordPlot()
function(input, output, session) {
output$plotPoints <- renderPlot({
replayPlot(p)
points(1:input$ile)
})
}
and ui.R:
library(shiny)
fluidPage(
sidebarPanel(
sliderInput("ile", min=1, max=10, label="", value=5)
),
mainPanel(
plotOutput("plotPoints"))
)
You said that you won't use plot, but it's important what you're going to use. For example, for ggplot you can do it like here (see reactive):
ui.R:
library(shiny)
fluidPage(
sidebarPanel(
sliderInput("ile", min=1, max=10, label="", value=5)
),
mainPanel(
plotOutput("plotPoints"))
)
server.R
library("shiny")
library("ggplot2")
data(iris)
function(input, output, session) {
wyk <- reactive({ggplot(iris)})
output$plotPoints <- renderPlot(
wyk() + geom_point(aes(x=Sepal.Length, y=Sepal.Width), col=input$ile)
)
}
Here is a little trick that should work if I understood your problem.
However, it's not R't, just a quick fix.
test/ui.R :
fluidPage(
sidebarPanel(
actionButton("trickButton","Useless"),
sliderInput("something", min=1, max=5, label="Useful", value=5)
),
mainPanel(
plotOutput("plotPoints")
)
)
test/server.R :
data(iris)
myData <<- NULL
superHeavyLoad <- function() {
print("That is super heavy !")
myData <<- iris
}
function(input, output, session) {
observe({
if (!input$trickButton)
superHeavyLoad()
})
output$plotPoints <- renderPlot(
plot(myData[,1:as.numeric(input$something)])
)
}
Now, on your R console :
require(shiny)
runApp("test")
Listening on http://127.0.0.1:7175
[1] "That is super heavy !"
And no matter what you do, you will never update the super-heavy part ever again.
Now, from what I understood, what you did is to divide your processing between heavy-one-time functions, and reactive things. This is a (not very beautiful) way of doing it ;-)
About how it works : it's all in the button that we add. The observe function will be called each time we interact with the button, plus at server start. The if(!input$trickButton) states that we just run our code at
server start (because then the button is not valued).
You could also hide this useless button with a renderUI mechanism.

Resources