Use Shiny Slider to Programmatically Control Size of Pie Charts

shiny

#1

I wish to have the user manipulate a slider to answer a question. To see if they are correct, the slider will move to the correct answer after they click, "Check". The pie chart will move at the same time. I wonder if this is possible using Shiny with the slider animation options. However, I do not know how to turn the animation on and off programmatically. Or if it's possible to have the slider decrease in value - to move from 80% to 60% for example.

You can simulate the desired behaviour if you run the "Shiny Slider Animation" code below. The slider starts at 60. Push play and push pause when the slider gets to 80. How is it possible to programmatically do the same thing? ie Press the "Check" button and the pie slice automatically expands from 40% to 60%.

My second thought was to try the R Package, pier, a wrapper for the d3pie javascript library. When I use a Shiny slider to update the pie chart, the entire chart is redrawn rather than updated. Is there a way around this? See code below, "Shiny and Pier".

Note: I posted a similar question on SO and received no response.

==== Shiny Slider Animation ====

library(shiny)
library(ggplot2)
library(scales)

ui <- fluidPage(
  
  
  # App title ----
  titlePanel("How Many Canadians Speak French?"),
  
  # Sidebar layout with input and output definitions ----
  sidebarLayout(
    
    # Sidebar to demonstrate various slider options ----
    sidebarPanel(
      
      # Size of slice A, B is determined automagically
      sliderInput("per_a", "Percent French Speaking",
                  min = 0, max = 100,
                  value = 60, step = 1,
                  animate = animationOptions(interval = 400, loop = TRUE)),
      actionButton(
        inputId = "check",
        label = "Check"
      )
    ),
    # Main panel for displaying outputs ----
    mainPanel(
      plotOutput(outputId = "pieChart")
      
    )
  )
)


# Define server logic for slider examples ----
server <- function(input, output, session) {
  df <- data.frame(
    group = c("English", "French"),
    value = c(40, 60)
  )
  
  # Functions
  draw_plot <- function(df) {
    bp <- ggplot(df, aes(x = "", y = value, fill = group)) +
      geom_bar(width = 1, size = 1, color = "grey23", stat = "identity")
    
    pie <- bp + coord_polar("y", start = 0)
    pie + 
      theme(axis.text.x = element_blank(),
            axis.title.x = element_blank(),
            axis.title.y = element_blank(),
            panel.border = element_blank(),
            panel.grid = element_blank(),
            legend.position = "none",
            axis.ticks = element_blank(),
            plot.title = element_text(size = 19, face = "bold")) +
      geom_text(aes(label = paste0(round(value), "% ", c("English", "French"))), 
                position = position_stack(vjust = 0.5), 
                color = "white", size = 6) +
      labs(x = NULL, y = NULL, title = "") +
      scale_fill_manual(values = c("red4", "#003399")) # Pie chart colours: English, French
  }
  
  output$pieChart <- renderPlot({
    df$value[2] <- input$per_a
    df$value[1] <- 100 - input$per_a
    draw_plot(df)
  })
  
  observeEvent(input$check, {
    answer <- 80 # True answer of number of French speakers in Canada
    updateSliderInput(session = session, inputId = "per_a", value = 80)
  })  
}

shinyApp(ui, server)

========= Shiny and Pier =======

library(shiny)
library(pier)

ui <- fluidPage(
  pierOutput("pier_example"),
  sliderInput("per_a", "Percent French Speaking",
              min = 0, max = 100,
              value = 60, step = 1)
)

server <- function(input, output) {
  
  output$pier_example <- renderpier({
    data.frame(
      value = c(input$per_a, 100 - input$per_a),
      label = c('Red', 'Blue'),
      color = c('Red', 'Blue')
    ) %>%
      
      # no options will default to 500px default
      # pier()
      
      # suggest defining size for initial render
      pier() %>% pie.size(width = 350, height = 350)
  })
}

shinyApp(ui = ui, server = server)


#2

In keeping with our guidelines on cross-posting, can you please add the link to your SO question? That way, if it starts attracting answers over there, nobody is duplicating effort here.