helgasoft / echarty

Minimal R/Shiny Interface to ECharts.js
https://helgasoft.github.io/echarty/
87 stars 3 forks source link

An exercise in binding charts | river chart with stacked barplot #30

Closed MrMisc closed 11 months ago

MrMisc commented 12 months ago

Hello again,

I was wondering if it was possible for you to show me how you would go about making 2 connected plots, a river plot and a stacked bar plot that are linked together. I am still figuring out how to do the calls with echarty, so unfortunately, I only have a version that I have been attempting in echarts4r recently that partially works, but appears to currently break in when it comes to the barplot.

##If you want to import from here
data<-read.csv("DirectExample.csv")

#River Plot
data|>group_by(Country)|>e_charts(Year)|>
  e_river(n)|>
  e_legend(right = 5,top = 30,bottom = 100,selector = "inverse",show=TRUE,icon = 'circle',emphasis = list(selectorLabel = list(offset = list(10,0))), align = 'right',type = "scroll",width = 10,orient = "vertical")|>
  e_theme("westeros")|>e_tooltip(trigger = "axis")|>
  e_datazoom(
    type = "slider",
    toolbox = TRUE,
    bottom = 10
  )|>
  e_title("ALL Anthrax Incident Reports by Year", "WAHIS Public Quantitative data from WHO")

#Bar plot
data|>group_by(Country)|>e_charts(Year)|>
  e_bar(n, stack = "group")|>
  e_legend(right = 5,top = 80,selector = "inverse",emphasis = list(selectorLabel = list(offset = list(10,0)), focus = "series"),show=TRUE,icon = 'circle',emphasis = list(selectorLabel = list(offset = list(10,0))), align = 'right',type = "scroll",width = 10,orient = "vertical")|>
  e_x_axis(min = min(data$Year)-1,max = max(data$Year)+1)|>
  e_tooltip()

#Attempt at combining both plots
data|>group_by(Country)|>e_charts(Year)|>
  e_river(n)|>
  e_legend(right = 5,top = 30,bottom = 100,selector = "inverse",show=TRUE,icon = 'circle',emphasis = list(selectorLabel = list(offset = list(10,0))), align = 'right',type = "scroll",width = 10,orient = "vertical")|>
  e_theme("westeros")|>e_tooltip(trigger = "axis")|>
  e_bar(n, stack = "group")|>
  e_x_axis(min = min(data$Year)-1,max = max(data$Year)+1)|>
  e_grid(right = 40, top = 100, width = "30%")

Currently the bar plot is a little buggy, as it doesn't quite show all the stacks. It does appear to work if I do something like this instead, but then the order of the Years is no longer respected.

data |> dplyr::mutate(Year = as.factor(Year)) |> group_by(Country) |> e_chart(Year) |> e_bar(n, stack = "group")

Lastly, my attempt at combining the 2 plots, does not work at all. It just produces a white screen. I am wondering if it would be possible for you to show me how you would go about tackling this problem with echarty instead, since I have been noticing a great deal more of versatility in echarty. I apologise for not having originally attempted it at echarty. I am interested to understand the syntax better to use it more regularly.

Thank you for your time

helgasoft commented 12 months ago

Learning from an "exercise" is fun, but translating from another library is less so. Your questions are interesting, please make an effort to code in echarty next time. Here we go:

raw <- read.csv("DirectExample.csv")
df <- raw |> select(Year,n,Country) |> arrange(Year) |> 
          mutate(Year=factor(Year, ordered=T))
legend <- list(type= "scroll",orient= "vertical", pageButtonPosition= 'start',
          right= 5,top = 30, icon = 'circle', align= 'right', height='85%')

priver <- ec.init(preset= F,
  series= list(list(type= 'themeRiver', 
                    data= ec.data(df), label= list(show=F))),
  singleAxis= list(min='dataMin', max= 'dataMax',
            axisLabel= list(formatter= htmlwidgets::JS("(x) => x.toString()"))),
  dataZoom= list(type= "slider", bottom= 10),
  legend= legend,
  tooltip= list(trigger = "axis"),
  title= list(text="ALL Anthrax Incident Reports by Year", 
              subtext="WAHIS Public Quantitative data from WHO")
)

pbar <- df |> group_by(Country) |> 
ec.init(
  series.param= list(type='bar', stack= "grp", encode= list(x='Year',y='n')),
  legend= legend,
  tooltip= list(show=T)
)

ec.util(cmd= 'tabset', River=priver, Bar=pbar)
# ec.util(cmd='layout', list(priver,pbar), cols=2)

image

About connecting the charts - please notice that they do not share the same data (bar is grouped, river is not). So I doubt connect is possible.

MrMisc commented 11 months ago

Regarding this dataset, could I get some insight into why the legend for the following does not quite work?

#Bar plot
raw<-read.csv("DirectExample.csv")

legend <- list(show = T,type= "scroll",orient= "vertical", pageButtonPosition= 'start',
               right= 5,top = 30, icon = 'circle', align= 'right', height='85%')

raw %>% mutate(Year = as.Date(paste0(raw$Year, "-01-01"))) |> group_by(Country) |>
  ec.init(
    series.param = list(type  ='bar',stack = "grp",encode = list(x = 'Year',y = 'n')),
    tooltip = list(show = T),
    legend = legend,
  )

The legned does not get sorted to the right and some of the bars appear to be floating from the output?

helgasoft commented 11 months ago

The legend does not get sorted to the right

I see it sorted to the right... image

some of the bars appear to be floating from the output

yes, because Year has been changed from type factor(value) to type time. Bars can be stacked only on a value xAxis. See docs.

MrMisc commented 11 months ago

Legend appears to still remain fully covering the entire screen on my side. Unfortunate that the example isn't reproducing so on yours.

Could you clarify for me what you mean by "factor(value)"? The Year column is originally in integer format and I can only conceive of maybe changing it to numeric (using as.numeric) if not just using integer to plot. However, the result destroys the individual stacked effect. For example

raw %>% mutate(Year = as.numeric(raw$Year)) |> group_by(Country) |>
  ec.init(
    series.param = list(type  ='bar',stack = "grp",encode = list(x = 'Year',y = 'n')),
    xAxis = list(max = 2030,min = 2004),
    tooltip = list(show = T),
    legend = legend,
  )

As of right now even trying to remove the legend does not seem to be working on my side either.

raw %>% mutate(Year = as.numeric(raw$Year)) |> group_by(Country) |>
  ec.init(
    series.param = list(type  ='bar',stack = "grp",encode = list(x = 'Year',y = 'n')),
    xAxis = list(max = 2030,min = 2004),
    tooltip = list(show = T),
    legend = list(show=FALSE),
  )
helgasoft commented 11 months ago

Sorry about "factor(value)", should be "factor(category)". You can use as.factor or as.character to create a category column.

legend <- list(show = T,type= "scroll",orient= "vertical", pageButtonPosition= 'start',
               right= 5,top = 30, icon = 'circle', align= 'right', height='85%')
raw %>% mutate(Year = as.character(raw$Year)) |> group_by(Country) |>
  ec.init(
    series.param = list(type  ='bar',stack = "grp",encode = list(x = 'Year',y = 'n')),
    tooltip = list(show = T),
    legend = legend,
  )

image

However, since Year is not sorted as in my original example, now the X axis is not in order.

MrMisc commented 11 months ago

Hmmm. A bit of a strange question, but given that, do you have a suggested mode to depict this data since it looks like barcharts are just fundamentally not suited for time series data like this?

I have been exploring alternatives like scatter plots for this type of data with the same underlying logic (pretty much identical), but scatter plots don't visually work very well, so I am a little stumped. I generally work with data in this scenario quite often.

helgasoft commented 11 months ago

The problem is probably not the chart type, but the sheer amount of data you are trying to present at once. data |> group_by(Year) |> summarize(cc=sum(n())) |> summarize(tot=sum(cc)) gives a total of 984 stacked bars. That is way to large for users to grasp. Maybe a "divide and rule" strategy will help, like "top 10 vs bottom 10", drill-down interactive maps or other categorizations. BTW stacked bars are very compact and suitable for size comparison, i.e. a good type choice.

MrMisc commented 11 months ago

I noticed that the bar chart doesn't break if I do make the set a little smaller (for instance, only plot from 2008 onwards instead of 2005).

Thank you for your help so far. Has been very useful.