Skip to contents

Rendering

The ui function is echartrOutput().

The server function is renderEchartr().

library(shiny)

shinyApp(
  ui = fluidPage(
    titlePanel("Echarts in Shiny"),
    echartrOutput("chart")
  ),
  server = function(input, output) {
    output$chart <- renderEchartr({
      echartr(option = list(
        xAxis = list(type = "value"),
        yAxis = list(type = "value"),
        series = ec_scatter(iris, 
          x = Petal.Width, 
          y = Petal.Length, 
          name = as.character(Species)
        )
      ))
    })
  }
)

Updating

By default, on each render the chart will be fully disposed of and recreated.

To override this behavior and update the existing chart, use update = TRUE in echartr():


# Toggle between two series to show the difference between updating and rerendering
series <- list(
  ec_scatter(iris, x = Petal.Width,y = Petal.Length, name = Species),
  ec_scatter(iris,x = Sepal.Width, y = Sepal.Length, name = Species)
)

shinyApp(
  ui = fluidPage(
    titlePanel("Echarts in Shiny"),
    echartrOutput("chart_replace"),
    echartrOutput("chart_update")
  ),
  server = function(input, output) {
    
    # Toggle the series every 2 seconds
    rv <- reactiveValues(series_index = 2L)
    current_series <- reactive({
      invalidateLater(2000L)
      
      isolate({
        rv$series_index <- 3L - rv$series_index
        series[[rv$series_index]]
      })
    })
    
    # Chart with default update = FALSE
    output$chart_replace <- renderEchartr({
      echartr(option = list(
        title = list(text = "Replace"),
        xAxis = list(type = "value"),
        yAxis = list(type = "value"),
        series = current_series()
      ))
    })
    
    # Chart with update = TRUE
    output$chart_update <- renderEchartr({
      echartr(update = TRUE, option = list(
        title = list(text = "Update"),
        xAxis = list(type = "value"),
        yAxis = list(type = "value"),
        series = current_series()
      ))
    })
  }
)

The other way to update an existing chart is with updateEchartr() within an observe().

Updating the option argument this way will avoid the recalculating state.

Another use of updateEchartr() is to dispatch actions. For example, updating which series is highlighted based on a selectInput:

series <- ec_scatter(
  iris, Petal.Length, Petal.Width, 
  name = as.character(Species),
  selectedMode = "multiple",
  silent = TRUE,
  itemStyle = list(opacity = 0.3),
  emphasis = list(
    itemStyle = list(opacity = 1)
  )
)

shinyApp(
  ui = fluidPage(
    titlePanel("Echarts in Shiny"),
    sidebarLayout(
      sidebarPanel(
        selectInput(
          "highlight", "Highlight: ", 
          choices = as.character(iris$Species),
          selected = 1
        )
      ),
      mainPanel(
        echartrOutput("chart")
      )
    )
  ),
  server = function(input, output) {
    
    output$chart <- renderEchartr({
      echartr(
        option = list(
          xAxis = list(type = "value"),
          yAxis = list(type = "value"),
          series = series
        ),
        dispatch = list(
          # Highlight initial selection immediately
          list(type = "highlight", seriesName = isolate(input$highlight))
        )
      )
    })
    
    # Update highlight based on input
    observe({
      updateEchartr(outputId = "chart", dispatch = list(
        list(
          type = "highlight", 
          seriesName = input$highlight
        ),
        list(
          type = "downplay", 
          seriesName = setdiff(as.character(iris$Species), input$highlight)
        )
      ))
    })
  }
)

Event listeners

Either renderEchartr() or updateEchartr() can be used to specify which event data to send to the server, via the listen parameter.

To de-register event listeners, you can use the off parameter of updateEchartr()

listeners <- c("click", "mouseover", "mouseout", "selectchanged", "legendselectchanged")

shinyApp(
  ui = fluidPage(
    titlePanel("Echarts in Shiny"),
    sidebarLayout(
      sidebarPanel(
        selectInput(
          "listen_to", "Listen to: ", 
          choices = listeners,
          multiple = TRUE
        ),
        h6("Latest event:"),
        verbatimTextOutput("events")
      ),
      mainPanel(
        echartrOutput("chart")
      )
    )
  ),
  server = function(input, output) {
    
    output$chart <- renderEchartr({
      echartr(option = list(
        xAxis = list(type = "value"),
        yAxis = list(type = "value"),
        legend = list(show = TRUE),
        series = ec_scatter(
          iris, Petal.Length, Petal.Width, 
          name = as.character(Species),
          selectedMode = "multiple"
        )
      ))
    })
    
    rv <- reactiveValues(
      listen_to = list(), # Track how listeners change
      latest_event = NULL
    )

    # Register which events to listen for
    observe({
      listen_to <- input$listen_to %||% character()
      
      updateEchartr(
        outputId = "chart",
        listen = setdiff(listen_to, rv$listen_to), # Add new listeners
        off = setdiff(rv$listen_to, listen_to) # Remove old listeners
      )
      
      rv$listen_to <- listen_to
    }) |>
      bindEvent(input$listen_to, ignoreNULL = FALSE)
    
    # Track the latest event
    observeEvent(input$chart_click, {
      rv$latest_event <- input$chart_click
    })
    observeEvent(input$chart_mouseover, {
      rv$latest_event <- input$chart_mouseover
    })
    observeEvent(input$chart_mouseout, {
      rv$latest_event <- input$chart_mouseout
    })
    observeEvent(input$chart_selectchanged, {
      rv$latest_event <- input$chart_selectchanged
    })
    observeEvent(input$chart_legendselectchanged, {
      rv$latest_event <- input$chart_legendselectchanged
    })
    
    # Display the latest event
    output$events <- renderPrint({
      if (is.null(rv$latest_event)) "No events yet" else rv$latest_event
    })
  }
)