I am new to R shiny, and Stack Overflow in general. I am trying to create my first dashboard. I have an API call that goes out and collects data from a website called The Blue Alliance. The Blue Alliance is a website that hosts data for high school robotics competitions.
However, in order for the API call to know what event to pull its data from, it needs an event code, which is one of the inputs from a dropdown menu in my UI. How can I make the whole API call reactive so that it subs in the input from the dropdown as part of the URL for the API call?
I have tried placing the reactive() before the #Pull Event Scoring comment by doing something like
reactive(Scores_S4 <- input$Event_Name)
I then tried using it to wrap my entire function, both with and without {} on either side of the parentheses. I have found on various websites they both suggest to and to not use {} when using the reactive function.
server <- function(input, output){
reactive(
#Pull Event live scoring
Scores_S1 <- "https://www.thebluealliance.com/api/v3/event/2022",
Scores_S2 <- input$Event_Name,
Scores_S3 <- "?X-TBA-AUTH-KEY *API Key Goes Here*",
FScores <- paste0(Scores_S1, Scores_S2, Scores_S3),
EScores <- fromJSON(FScores),
EScores <- as.data.frame(EScores)
RPP1 <- ggplot(EScores, aes(reorder(`TeamName`, -`Avg. Hang`), `Avg. Hang`)) + geom_point()
output$RPPP1 <- renderPlot(RPP1))
}
I know that the API call is correct if the value of input$Event_Name is put in, I just need help understanding the reactive portion so that it uses current widget outputs while the app is running. In my understanding, if done correctly, this will allow my ggplot function to create a new graph depending on what is chosen for the input$event. I have a call to "plot output("RPPP1")" in my UI, so this should work once I understand the reactive piece.
Thank you for any and all time put into this, it is all helping a great deal to learn from a community this great.
Something like this might work:
EScores <- reactive({
#Pull Event live scoring
Scores_S1 <- "https://www.thebluealliance.com/api/v3/event/2022"
Scores_S2 <- input$Event_Name
Scores_S3 <- "?X-TBA-AUTH-KEY *API Key Goes Here*"
FScores <- paste0(Scores_S1, Scores_S2, Scores_S3)
EScores <- fromJSON(FScores)
as.data.frame(EScores)
})
output$RPP1 <- renderPlot({
ggplot(EScores(), aes(reorder(`TeamName`, -`Avg. Hang`), `Avg. Hang`)) + geom_point()
output$RPPP1 <- renderPlot(RPP1))
})
But, presumably you'll need something between
FScores <- paste0(Scores_S1, Scores_S2, Scores_S3),
and
EScores <- fromJSON(FScores),
that actually makes a call to the API, like curl() or GET().
Related
I webscraped 2 tables (A and B). Then I merge them by rows (rbind). When I launch it, everything is ok. When I wanna use it in shiny app there is something wrong. Below structure of tables and what shiny shows. Any suggestion? Where could be the problem? Unfortunatelly, I can not show the code, because this is for my thesis. I would be very grateful for your help.
As you can see the problem is with third column. B table has all rows with NA. After merge, all data from A table has also NA.
In shiny table is showed by renderTable.
Structure of tables A and B
I have no answer for your question, but I would like to write something and there is not enough space for this in comment section, so I will write this as answer and eventually delete later. So - I rather believe that there is something wrong with your code which you use inside shiny and would like to check this with your help. I assume you need some help with debugging, so I will post a code below:
library(shiny)
ui <- fluidPage(
tableOutput("table")
)
server <- function(input, output, session) {
my_df <- reactive({
data.frame(a = c(1, 2, 3),
b = c(4, 5, 6))
})
output$table <- renderTable({
my_df()
browser()
})
}
shinyApp(ui, server)
In the code above I have made one output (table output) and - on the server side in reactive - I'm creating data.frame. Then I use this reactive function inside my output (output$plot). However, the last line inside output$plot is function browser() which is used for debugging. You can try my code in your console and see that when you run shiny app, it immediately moving back to console (but this is "dubugging state", so console looks a little different, for example there is a button "stop" with red square which can be use to close debugging state). Please run my shiny app and when you will be back in the console, in the debugging state, type my_df() to see the data.frame object. Could you please do the same with your shiny app? I mean, could you use browser() function on the last line in your renderTable? And come back and tell if the last column contains only NA or not when displayed in the console? If not, then I would say that you are doing something different in Shiny than manually with your tables.
I've created a scatter plot with ggplot2 and would like to link the data points with corresponding sound files. In a shiny app it should then be possible to click on or hover over a data point to play the sound file. While I manage to get the plot into a shiny app, I am struggling with the inclusion of tags$audio, as described here, into the plot.
library(shiny)
library(plotly)
ui <- fluidPage(
plotlyOutput('scatter')
)
server <- function(input, output) {
output$scatter <- renderPlotly({
ggplotly(p)
})
}
shinyApp(ui = ui, server = server)
The plotly plot displays a tooltip with the info per data point, among others also the URL for the sound file. See the working example here: https://chart-studio.plotly.com/~petergi/1.
The ggplot2 code contains the URL information in the aes 'text'.
p <- ggplot(without_outliers) +
aes(x = T2, y = T1, label = labels, col = next_label,
text = paste0("URL: ", "https://www.yyyy.zz/audio/", tolower(bundle), ".mp3"))
Any hint to how to bring an audio player to the scatter plot's data points in shiny would be highly appreciated.
In the meantime, I found a working solution in using the R package ggiraph, which enhances ggplot2 with tooltip and onclick functionalities, when used in a shiny application. In a nutshell, a geom_point_interative call can have an onClick argument, which in turn then is a call to a Javascript function to play the audio (without opening a new window or a player).
library(ggplot2)
library(ggiraph)
library(shiny)
p <- ggplot(mtcars, aes(wt, mpg))+
geom_point_interactive(onclick="var audio= new Audio(\"https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_700KB.mp3\"); audio.play();")
x <- girafe(ggobj = p)
To allow for all different data points in a data frame to be associated with their corresponding audio files, the data frame should be modified to contain a new column with the individual javascript code to play the audio.
An example shiny app can be found here.
Thank you Peter, I managed to get this working with help from your pointers. I know this is a late response but I hope it helps if someone else runs into a similar issue. First, I recommend reviewing the examples shared above.
I managed to get something like this working. However, instead of defining the audio and playing it with the onclick argument, I created a separate javascript file and sourced it through the shiny applet.
I created a separate file called fileNames.js where I defined each variable. Using the example above with only one audio file, this would be: var audio= new Audio("https://file-examples.com/wp-content/uploads/2017/11/file_example_MP3_700KB.mp3");.
In the R shiny applet, I changed the onclick argument in geom_point_interactive() to the javascript code to play the audio file. In your example, the string would be simply audio.play();. For whatever reason passing the multi-line javascript code to the onclick argument didn't work for me.
Early in the ui call, I included includeScript(path = "fileNames.js") to source the javascript into the shiny app.
Here's another helpful example in case someone stumbles upon this thread as I did: https://www.ardata.fr/en/post/2019/05/24/whats-up-ggiraph/
I am wanting to write a program in Shiny that will keep up with the response time taken to interact with various objects. The simplest analogue would be something like a timed matching game wherein the user must select a specific object/stimulus, and I want to be able to find out later (i.e., after the application is finished) how long each response took and whether it was correct.
I already know how to do most of this program; however, I cannot find anyway within Shiny to keep up with response time let alone as a function of interaction with a reactive element. Based on preliminary searches, it seems like Javascript may have a solution; however, I know zero Javascript experience and also don't have any experience integrating it with Shiny.
Does anyone know of a way of using existing R/Shiny language to perform a count-up timer that could be used to time responses to multiple objects? Alternatively, does anyone have a potentially better solution to timing responses that I may be missing?
EDIT: ABOVE ISSUE ADDRESSED, BUT NEW ONE HAS COME UP IN AN EXTENSION OF THE ANSWER
I initially left this as a comment, but it was too long to fit in the length requirements. I've come up with a new issue. This time, I want to keep a running tab of how long it has taken between any two clicks but without knowing how many clicks a user may submit. I've played around some with the code given, but I can't get it to work (relevant pieces below, nothing else was changed):
if(total_timestamps == 2){
duration <- rbind(duration, as.numeric(difftime(new_val[2],new_val[1],units = "secs")))
new_val[1] <- new_val[2]
new_val <- new_val[-2, ]
click_timestamps(new_val)
### other things to do
}
My thought was to switch the old and new values and then delete the oldest value to make room for a new one to continue the cycle, but it's not working as I had hoped. Thoughts or help?
You don't need JavaScript for this. You can create a reactive value, and append value to it each time an element is clicked. If you need to observe multiple different elements, then just write more observers.
library(shiny)
ui <- fluidPage(
actionButton("button","Click"),
tags$h2("Response Time"),
tags$div(id = "duration")
)
server <- function(input, output, session) {
click_timestamps <- reactiveVal(NULL)
observeEvent(input$button,{
new_val <- append(click_timestamps(),Sys.time())
# set click timestamp
click_timestamps(new_val)
total_timestamps <- length(new_val)
if(total_timestamps == 2){
duration <- as.numeric(difftime(new_val[2],new_val[1],units = "secs"))
insertUI(
selector = "#duration",
ui = tags$p(paste0("Seconds between clicks: ", duration))
)
# reset click timestamp
click_timestamps(NULL)
}
})
}
shinyApp(ui, server)
I have been using R for about a year but am only a few weeks into Shiny. I have some code which calls an API and spits out a nice tables of results which I would like to use in a Shiny App - with the API being called when an action button is clicked.
I've been trouble shooting this for a few days but can't figure it out, below are a few of the things I have tried.
If I remove the action button, the API calls and displays as soon as the app is opened.
Replacing the API with simple text shows the text when the button is clicked.
Rendering the table inside the action results in the UI wondering where the table is (as button as not been pressed) and giving an error.
The API contains sensitive info so I have removed some details added a typical return (it returns Json to the browser when URL is visited).
Any ideas on what i might be missing?
API return
{"meta":{"request":{"granularity":"Monthly","main_domain_only":false,"format":null,"domain":"cnn.com","start_date":"2017-02-01","end_date":"2017-02-28","limit":null,"country":"world"},"status":"Success","last_updated":"2017-04-30"},"visits":[{"date":"2017-02-01","visits":100000`}]}
UI.r
library(shiny)
shinyUI(fluidPage(
headerPanel(actionButton("do", "Click Me")),
mainPanel(dataTableOutput("mytable"))
))
Server.r
library(shiny)
function(input, output) {
#Call API, flatten Json return
Visits_Final<- eventReactive(input$do, {
Results<- paste0("https://api.com/",
"site.com",
"apikey=***") %>%
map(fromJSON, flatten = FALSE)
#Transform into DF
visits_temp= data.frame(date=NA,visits=NA,ID=NA)
for(i in 1:1){
DF_L<- as.data.frame(Results[[i]]$visits)
ID <- (rep(i, nrow(DF_L)))
DF_L<- cbind(DF_L, ID)
Visits_Final<-rbind(visits_temp, DF_L)}})
#Output to UI
output$mytable <- renderDataTable({Visits_Final()})
}
Thanks in advance!
Edits
for(i in 1:i){
As per BigDataScientist comment, changed to
for(i in 1:1){
Code comments added
System info added:
R 3.3.2
R Studio Version 1.0.143
OS Sierra 10_12_3
Solved - In the Server file I changed eventReactive to observeEvent
Honestly, not 100% understanding this documentation but it did help
Shiny: what is the difference between observeEvent and eventReactive?
Feel free to comment with similar problems.
I'm drafting a simple Shiny App that provides access to a dynamic chart and a corresponding table. The relevant part of the server.R code looks like that:
output$some_plot<- renderPlot({
# Subset data on change in the indicator selection
chrt_demo_dta <- subset(x = dta_la_demo,
subset = <<my-conditions>>>)
# Define the demography chart
ggplot(data = chrt_demo_dta, aes(x = variable_a, y = variable_b)) +
geom_line(aes(colour = GEOGRAPHY_NAME), size = 2) +
theme_bw()}, height = 650, width = 800)
# Section generating table
output$chrt_demo_dta_tbl <- renderTable({chrt_demo_dta})
The problem occurs when I try to access the table I get the following error message:
Error in func() : object 'chrt_demo_dta' not found
It appears that the object chrt_demo_dta is created outside the scoping rules of the renderTable. My question is how can I achieve the following:
I want for the chart and the corresponding table to update dynamically upon the selection, hence my idea to embed the subset command in the renderPlot which works
I want to make use of the same subset in a corresponding table. Ideally, I would like to avoid repeating the subset command. As I have the required data frame ready it appears that it is only a matter of accessing it via the renderTable
I'm aware the the code is not fully reproducible but at this stage I'm not necessarily looking for a particular solution but a more generic guidance whether it would be possible to access an object created within one server element from other server element. If the push comes to shove, I could encapsule the subsetting mechanism in a function and call it twice but it seems to be rather messy solution.
In the server function of server.R:
# Create reactive object w/in server func
chrt_demo_dta <- reactiveVal()
output$some_plot<- renderPlot({
chrt_demo_dta.temp <- subset(
x = dta_la_demo,
subset = <<my-conditions>>>)
# Update the obj within scope of nested function
chrt_demo_dta(chrt_demo_dta.temp)
})
# Access of the updated obj is now possible in original scope
output$chrt_demo_dta_tbl <- renderTable({chrt_demo_dta()})
See related: Shiny : How to modify reactive object
The <<- operator may have unwanted consequences. It sends results to the shared environment, where it is visible to all users of the session. Not only will this create a race-condition where they try to over-write each other, it may expose confidential work to others. You have two solutions: 1) repeat the steps in each local environment, 2) write the result to disk with a unique name (e.g. Sys.time() + data hash). Then you can retrieve it when needed elsewhere. Don't forget to delete the saved file though, or your storage will be consumed.