Search code examples
chartsgoogle-visualizationamchartsamcharts4

Is it possible to use stacked column chart without the series adding up?


First of all, I am not sure if what I am looking for is called stacked column chart or else.

Lib is either Google Charts or amCharts.

I have a series of values for the last 28 days representing e-mails sent, e-mails opened and e-mails with links clicked. For each date, the column's max. value should be the number of e-mails sent. This column is then divided based on the two other values. Basically what the chart should show is that from 20 mails sent, 17 were opened and 5 even had people click links inside them. With a regular stacked column approach and the numbers 20, 17 and 5, this would render a column peaking at 42 with one section covering 0-20, one 20-37 and one 37-42. What I want is a column peaking at 20, in front of it a column peaking at 17 and in front of that a column peaking at 5. Similar to a diff chart.

I could theoretically achieve this by modifying my data taking the 5 mails with clicks, the opened mails are 17 minus 5 = 12 and the mails sent are 20 minus 17 = 3. Then 5+12+3 = 20 what I wanted. However, hovering the stacked column will display the wrong values 5, 12 and 3 in the tooltip instead of 5, 17 and 20. So I would have to render custom tooltips.

You guys have any idea if there is a simple solution for my problem?


Solution

  • for the scenario you describe theoretically,
    you would not need custom tooltips.

    when loading the google data table, we can use object notation.
    we can provide the value (v:), and the formatted value (f:)

    {v: 12, f: '17'}
    

    the tooltip will use the formatted value by default.

    in addition, you could use a DataView to perform the calculation.
    which would allow you to load the data as normal.

    here, calculated columns are used to adjust the value that is plotted,
    but display the original value.

    see following working snippet...

    google.charts.load('current', {
      packages: ['corechart']
    }).then(function () {
      // create data table
      var data = new google.visualization.DataTable();
      data.addColumn('string', 'Date');
      data.addColumn('number', 'Emails with Clicks');
      data.addColumn('number', 'Emails Opened');
      data.addColumn('number', 'Emails Sent');
    
      // add data
      data.addRow(['06/2020', 5, 17, 20]);
    
      // create number format
      var formatNumber = new google.visualization.NumberFormat({
        pattern: '#,##0'
      });
    
      // create data view
      var view = new google.visualization.DataView(data);
    
      // build view columns
      var viewColumns = [0];
      for (var i = 1; i < data.getNumberOfColumns(); i++) {
        addColumn(i);
      }
      function addColumn(index) {
        viewColumns.push({
          calc: function (dt, row) {
            var currentColumnValue = dt.getValue(row, index);
            var previousColumnValue = 0;
            if (index > 1) {
              previousColumnValue = dt.getValue(row, index - 1);
            }
            var adjusttedColumnValue = currentColumnValue - previousColumnValue;
            var formattedColumnValue = formatNumber.formatValue(currentColumnValue);
            return {
              v: adjusttedColumnValue,
              f: formattedColumnValue
            };
          },
          label: data.getColumnLabel(index),
          type: data.getColumnType(index),
        });
      }
    
      // set view columns
      view.setColumns(viewColumns);
    
      // create options
      var options = {
        chartArea: {
          left: 64,
          top: 40,
          right: 32,
          bottom: 40,
          height: '100%',
          width: '100%'
        },
        height: '100%',
        isStacked: true,
        legend: {
          alignment: 'end',
          position: 'top'
        },
        width: '100%'
      };
    
      // create, draw chart with view
      var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
      chart.draw(view, options);
      window.addEventListener('resize', function () {
        chart.draw(view, options);
      });
    });
    html, body {
      height: 100%;
      margin: 0px 0px 0px 0px;
      overflow: hidden;
      padding: 0px 0px 0px 0px;
    }
    
    .chart {
      height: 100%;
    }
    <script src="https://www.gstatic.com/charts/loader.js"></script>
    <div class="chart" id="chart_div"></div>


    Note: If you want to stack columns, one in front of the other, similar to a Diff Chart,
    check this answer...

    Google Chart - More then 1 difference column