I am trying to create an animated gauge chart that changes according to specific values defined in a vector. This is for a shiny app in R. I am currently using the C3 library, but there is no restraint. I do want code this in R with shiny.
The code below does something similar, but the animation runs with random values. I want to set specific values for each frame of the animation.
runApp(list(
ui = bootstrapPage(
# example use of the automatically generated output function
column(6, C3GaugeOutput("gauge1"))
),
server = function(input, output) {
#riskList <- c(10,20,30,40,50,60,70,80,90,100)
# reactive that generates a random value for the gauge
value = reactive({
invalidateLater(1000)
round(runif(1,min=0,max=100),2)
})
# example use of the automatically generated render function
output$gauge1 <- renderC3Gauge({
# C3Gauge widget
C3Gauge(value())
})
}
))
The output should be similar to what we get when using animated charts in plotly with the frame parameter. I should have an input vector (c(10,20,30,40,50), for example), a play button and a gauge chart as output. I want the gauge to show and output of 10, then 20, then 30 and so on, once I click the button.
Try this approach using application state variables and a constantly re-validating gauge_value.
library(c3)
library(shiny)
ui <- fluidPage(
c3Output("gauge1"),
actionButton("start_button", "Start Engines")
)
server <- function(input, output, session) {
gauge_breaks <- seq(0, 100, 10)
is_animating <- FALSE
current_index <- 1
observeEvent(input$start_button, {
current_index <<- 0
is_animating <<- TRUE
})
gauge_value = reactive({
invalidateLater(1000)
if(is_animating)
current_index <<- current_index + 1
if(current_index == length(gauge_breaks))
is_animating <<- FALSE
data.frame(rpm = as.numeric(gauge_breaks[current_index]))
})
output$gauge1 <- renderC3({
c3_gauge(c3(gauge_value()))
})
}
While I do not like using the <<-
operator, I found this version to be easier to understand than another version which stored the current index in a numericInput
hidden inside an always hidden conditionalPanel
. That approach required an isolate()
in order to adhere to the invalidateLater()
as opposed to updating the gauge_value()
immediately every time the index changed.