echarts4r icon indicating copy to clipboard operation
echarts4r copied to clipboard

Morphing possible between scatter and aggregated bar charts?

Open rdatasculptor opened this issue 2 years ago • 9 comments

Hi @JohnCoene!

Just wondering. Do you think it is possible to use the new morph-function for a tranistion between a scatter plot and a bar plot?

This is an example of what I mean. It uses an avarage calculation function and uses it as a value in data, but I have no idea how to incoporate this in in echarts4r.

Thanks in advance!

rdatasculptor avatar Sep 28 '22 12:09 rdatasculptor

@rdatasculptor, calculating averages is on the data preparation stage, not related to visualization. No need to use JS for it since R has function mean() and others to do the same job. Just build the two data/charts and plug them into e_morph - should work.

helgasoft avatar Sep 29 '22 17:09 helgasoft

@helgasoft yes, I am aware of the possibilities within R itself, but with that approach there is no real morph. In the example of echarts the bars seem to be build of all the pieces of data the avarage is taken from. So the issue I am aimin at is the smoothness of the trainsition of scatter plot into the bar chart. If I have some more time I will show what I mean with an example.

rdatasculptor avatar Sep 29 '22 19:09 rdatasculptor

Could be integrated but evaluating R code via htmlwidgets is less than ideal, is it for shiny or Rmd?

JohnCoene avatar Sep 29 '22 20:09 JohnCoene

It's for Rmd. (I always intend to not be too dependent on shiny, and thanks too echarts4r I succeed very often :))

rdatasculptor avatar Sep 29 '22 20:09 rdatasculptor

Hi @JohnCoene! I don't know if it is of any worth, but using e_list() is at least one way to bring @helgasoft's example of smooth transition between differenct plot types, mentioned here, to echarts4r:

library(dplyr)
library(echarts4r)
mc <- mtcars |> filter(cyl<8)
datt <- function(idx) { return(mc[mc$cyl==idx,]$hp) }
colors <- c("blue","red")

oscatter <- list(
  title= list(subtext='press button to morph'),
  xAxis= list(scale=TRUE),
  yAxis= list(scale=TRUE), color= colors,
  series=list(
    list(type='scatter', id=4, dataGroupId=4, data= datt(4),
         universalTransition= list(enabled= TRUE)),
    list(type='scatter', id=6, dataGroupId=6, data= datt(6),
         universalTransition= list(enabled=TRUE)) 
  )
)
obar <- list(
  title= list(text= 'Average'),
  xAxis= list(type= 'category', data= list('cyl4', 'cyl6')),
  yAxis= list(show= TRUE), color= colors,
  series= list(list(
    type= 'bar', id= 'average', colorBy= 'data',
    data= list(
      list(value= mean(datt(4)), groupId=4),
      list(value= mean(datt(6)), groupId=6)),
    universalTransition=list(enabled= TRUE, 
                             seriesKey=c(4, 6))
  ))
)

e1 <- e_charts() |>
  e_list(obar)
e2 <- e_charts() |>
  e_list(oscatter)

e_morph(e1, e2, callback = cb) %>% 
  htmlwidgets::prependContent(
    htmltools::tags$button("Toggle", id = "toggle")
  )

e_morph(e1, e2, callback = cb) %>% 
  htmlwidgets::prependContent(
    htmltools::tags$button("Toggle", id = "toggle")
  )

Maybe it generates new ideas? Somehow the charts should be connected by id's and dataGroupIds. I guess I can add them to the lists programmattically, but haven't succeeded yet in doing that properly (in finding a generic way)

rdatasculptor avatar Nov 10 '22 20:11 rdatasculptor

Another attempt with an example script of my own. Obviously I overlook something or I misunderstand the docs about universal transition, but using dataGroupId should be at least one of the necassary ingredients. Th example below gives a transition but not the transition what I am looking for: bar chart breaking into smaller pieces and turning into the scatter plot.

df <- data.frame(nummer = 1:10, y1 = sample(1:100, 10), group=as.character(sample(1:2, 10, replace = TRUE)))
e1 <- df %>% 
  e_charts(nummer) %>%
  e_scatter(y1, symbol_size = 20, 
            dataGroupId =  = "data",
            universalTransition = list(enabled= TRUE, 
                                       seriesKey= "data")),
            animationDurationUpdate = 1000L)

e2 <- df %>% group_by(group) %>% summarise(y1 = sum(y1)) %>% ungroup() %>%
  e_charts(group) %>%
  e_bar(y1, 
        dataGroupId = "data",
        universalTransition = list(enabled= TRUE, 
                                   seriesKey= "data", divideShape = "clone"),
        animationDurationUpdate = 1000L)

cb <- "() => {
  let x = 0;
  document.getElementById('toggle')
    .addEventListener('click', (e) => {
      x++
      chart.setOption(opts[x % 2], true);
    });
}"

e_morph(e1, e2, callback = cb) %>% 
  htmlwidgets::prependContent(
    htmltools::tags$button("Toggle", id = "toggle")
  )

rdatasculptor avatar Nov 12 '22 10:11 rdatasculptor

Hi @JohnCoene, sorry for bothering you again, but I kind of succeeded in making a smooth transition between a scatter plot and a bar chart. (@helgasoft put me in the right direction). I still don't know exactly what I am doing, but it works.... :) But this approach needs some tweaks in the object structure. First I turn the echarts4r object into a list, then I do the tweaks, and finally I render the plots using e_list(). Maybe you can find a way (if you have time ofcourse...) to somehow make it possible to these kind of transitions without needing to tweak before rendering? But then again, maybe it is harder to implement such a feature than I think.

Here is a wokring example of the smooth transition:

library(echarts4r)
library(dplyr)

set.seed(2022)
df <- data.frame(nummer = 1:10, y1 = sample(1:100, 10), 
                 group=as.character(sample(1:2, 10, replace = TRUE))) %>% dplyr::group_by(group)

oscatter <- df %>%
  e_charts(nummer) %>%
  e_scatter(y1, symbol_size = 20) %>% e_inspect()
oscatter$series[[1]]$universalTransition <- list(enabled = TRUE, seriesKey = c(1))
oscatter$series[[2]]$universalTransition <- list(enabled = TRUE, seriesKey = c(2))
oscatter$series[[1]]$id <- 1
oscatter$series[[2]]$id <- 2
oscatter$series[[1]]$dataGroupId <- 1
oscatter$series[[2]]$dataGroupId <- 2
oscatter <- e_charts() %>%
  e_list(oscatter) 

obar <- df %>% summarise(y1 = sum(y1)) %>% ungroup() %>% 
  e_charts(group) %>%
  e_bar(y1, colorBy= "data", universalTransition = list(enabled= TRUE)) %>% e_inspect() 
obar$series[[1]]$data[[1]]$groupId <- 1 
obar$series[[2]]$data[[1]]$groupId <- 2
obar$series[[1]]$universalTransition <- list(enabled = TRUE, seriesKey = c(1,2))
obar <- e_charts() %>%
  e_list(obar) 

cb <- "() => {
  let x = 0;
  document.getElementById('toggle')
    .addEventListener('click', (e) => {
      x++
      chart.setOption(opts[x % 2], true);
    });
}"

e_morph(oscatter, obar, callback = cb) %>% 
  htmlwidgets::prependContent(
    htmltools::tags$button("Toggle", id = "toggle")
  )

rdatasculptor avatar Nov 16 '22 10:11 rdatasculptor

If someone can find a solution for not being able to morph between bar charts and scatter plots using echart4r (@munoztd0 .. :)), well, for me he earns the nobel prize ....

rdatasculptor avatar Oct 10 '23 19:10 rdatasculptor

In my imagination we just give the scatterplot and the bar chart that should be morphed into one another the same "morph id". Under the hood echarts4r takes care of all the necessary echarts settings :). Experimented with it, but haven't made it work yet.

rdatasculptor avatar Oct 28 '23 21:10 rdatasculptor