Is it possible to add and remove a mark line using a proxy so that the chart doesn't get fully redrawn?
To illustrate what it would look like:
library(shiny)
library(echarts4r)
df <- data.frame(
x = 1:100,
y = runif(100)
)
ui <- fluidPage(
actionButton("add", "Add series"),
actionButton("rm", "Remove series"),
echarts4rOutput("chart")
)
server <- function(input, output){
output$chart <- renderEcharts4r({
e_charts(df, x) %>%
e_scatter(y, z)
})
# e_mark_line() - has id added for this example
observeEvent(input$add, {
echarts4rProxy("chart", data = df, x = x) %>%
e_mark_line(
id = "my_line"
, data = list(xAxis = 50)
, title = "Line at 50") %>%
e_execute()
})
# e_remove_mark_line() - is made up for this example
observeEvent(input$rm, {
echarts4rProxy("chart") %>%
e_remove_mark_line("my_line")
})
}
shinyApp(ui, server)
It's a bit odd. Apparently, a 'mark line' is attached to a specific series. I didn't add handlers for the id
field, it can be done, though. However, you would also have to specify the trace it's attached to.
BTW: in your code, you wrote e_scatter(y, z)
, but there is no z
.
The easiest method is to create a function like the one you eluded to in your code.
There are two custom functions. One for Shiny in R code. One for the browser in Javascript. Combined, these create the function e_remove_markLine_p
.
The R function (specifically for Shiny applications)
e_remove_markLine_p <- function (proxy)
{
opts <- list(id = proxy$id)
proxy$session$sendCustomMessage("e_remove_markLine_p", opts)
return(proxy)
}
The JS function
Shiny.addCustomMessageHandler('e_remove_markLine_p',
function(data) {
var chart = get_e_charts(data.id);
let opts = chart.getOption();
if(opts.markLine.length > 0) {
opts.markLine.length = 0; /* remove data */
}
chart.setOption(opts, true);
})
Using the power of Shiny, these two functions carry the request from the browser to R & back to the browser.
In the code, I've changed a few other things. Instead of e_mark_line
, I used e_mark_p
. I'm not sure if it matters, but per the documentation, that's the appropriate function.
Here's the entire app altogether.
library(tidyverse)
library(echarts4r)
library(shiny)
set.seed(315)
df <- data.frame(x = 1:100, y = runif(100))
# custom function for 'e_remove_markLine_p',
e_remove_markLine_p <- function (proxy)
{
opts <- list(id = proxy$id)
proxy$session$sendCustomMessage("e_remove_markLine_p", opts)
return(proxy)
}
ui <- fluidPage(
# adds the same call to both add and remove buttons
tags$head(
tags$script(HTML("
Shiny.addCustomMessageHandler('e_remove_markLine_p',
function(data) {
var chart = get_e_charts(data.id);
let opts = chart.getOption();
if(opts.markLine.length > 0) {
opts.markLine.length = 0; /* remove data */
}
chart.setOption(opts, true);
})
"))),
actionButton("add", "Add series"),
actionButton("rm", "Remove series"),
echarts4rOutput("chart")
)
server <- function(input, output){
output$chart <- renderEcharts4r({
e_charts(df, x) %>%
e_scatter(y) # <--- I removed z, since it doesn't exist...
})
observeEvent(input$add, {
echarts4rProxy("chart", data = df, x = x) %>%
e_mark_p(type = "line",
data = list(xAxis = 50),
title = "Line at 50") %>%
e_merge() %>% e_execute() # merge when adding to the plot
})
observeEvent(input$rm, {
echarts4rProxy("chart") %>%
e_remove_markLine_p() # remove all "mark" lines
})
}
shinyApp(ui, server) # show me what you got