Is there a way to animate a gauge in R, according to specific values from a vector?

Viewed 361

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.

1 Answers

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.

Related