Search code examples
rechartsecharts4r

eCharts(4r) bar plot - how to prevent x-axis categories from being plotted if there is no data


How can I adjust an echart so that if there is no data for a combination of x-axis category and grouping variable, the empty space is removed?

ie in the chart below, the group2/A combo and the group1/C combo have no data, so I would like for the space for them to be removed.

Example:

library(tidyverse)
library(echarts4r)
x <- rep(c("A", "B", "C"), each = 100)
y <- rep(c("group1", "group2"), each = 150)
z <- runif(300, max = 10)

df <- tibble(x, y, z)

df %>% 
  group_by(y) %>% 
  e_charts(x) %>% 
  e_bar(z)

enter image description here

I have seen a potential solution using a custom serie, but my actual use case has many bars and I'd prefer to have an automatic solution rather than having to specify the width of each individual bar.

While I'm doing this in R, I can translate Javascript solutions.


Solution

  • I dont think there is an out of the box solution for your issue.

    The best I could think of is using xAxis: {type: 'value'}, sorting the data by categories (A,B,C,..) in ascending order and using a visualMap to color them according to their respective group.

    Currently I dont have a good solution for the xAxis label. What could be done to differentiate the different categories is adding one series for each category and apply some styling other than color.

    Here is an example:

    // some random data
    const data = [[],[],[],[]];
    const categories = ['A', 'B', 'C', 'D'];
    for (let i = 1; i <= 20; i++) {
      const idx = Math.floor((i - 1) / 5);
      data[idx].push({id: i, category: categories[idx] , group: Math.ceil(Math.random() * 2), value: Math.random() * 100})
    }
    
    option = {
      aria: {
        enabled: true,
        decal: {show: true},
      },
      dataset: [
        {source: data[0]},
        {source: data[1]},
        {source: data[2]},
        {source: data[3]},
      ],
      xAxis: {
          type: 'value',
          axisLabel: {show: false},
          axisTick: {show: false},
      },
      yAxis: {
        type: 'value'
      },
      visualMap: [
        {
          type: 'piecewise',
          dimension: 2,
          categories: [1,2],
          inRange: {
            color: ['lightblue', 'lightgreen']
          },
          top: 10,
          right: 10,
        },
      ],
      series: [
        {
          type: 'bar',
          name: 'A',
          datasetIndex: 0,
          encode: {
            x: 'id',
            y: 'value',
          },
          itemStyle: {borderWidth: 2, borderColor: 'red'},
        },
        {
          type: 'bar',
          name: 'B',
          datasetIndex: 1,
          encode: {
            x: 'id',
            y: 'value',
          },
          itemStyle: {borderWidth: 2, borderColor: 'black'},
        },
        {
          type: 'bar',
          name: 'C',
          datasetIndex: 2,
          encode: {
            x: 'id',
            y: 'value',
          },
          itemStyle: {borderWidth: 2, borderColor: 'orange'},
        },
        {
          type: 'bar',
          name: 'D',
          datasetIndex: 3,
          encode: {
            x: 'id',
            y: 'value',
          },
          itemStyle: {borderWidth: 2, borderColor: 'purple'},
          barGap: -1,
        },
      ]
    };
    

    Note, that for some reason you need to add barGap: -1, for the bars to not be miles aprat.