0

I need to plot the values from lowest to highest in amcharts 4 stack column chart, Right now stack column chart series is formed based on the series we are creating. Example-series not aligned in Ascending order

I am expecting a solution of how to plot values in Ascending order. From the below Example the graph is plotted based on series not on values. So how plot the graph based on series but values to be plotted in ascending order

// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end

// Create chart instance
var chart = am4core.create("chartdiv", am4charts.XYChart);


// Add data
chart.data = [{
  "year": "2016",
  "europe": 5.5,
  "namerica": 2.5,
  "asia": 2.1,
  "lamerica": 0.3,
  "meast": 0.2,
  "africa":4.1
}, {
  "year": "2017",
  "europe": 4.6,
  "namerica": 2.7,
  "asia": 2.2,
  "lamerica": 0.3,
  "meast": 0.3,
  "africa": 2.1
}, {
  "year": "2018",
  "europe": 3.8,
  "namerica": 2.9,
  "asia": 2.4,
  "lamerica": 0.3,
  "meast": 0.3,
  "africa": 3.1
}];
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "year";
categoryAxis.renderer.grid.template.location = 0;


var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.inside = true;
valueAxis.renderer.labels.template.disabled = true;
valueAxis.min = 0;

// Create series
function createSeries(field, name) {
  
  // Set up series
  var series = chart.series.push(new am4charts.ColumnSeries());
  series.name = name;
  series.dataFields.valueY = field;
  series.dataFields.categoryX = "year";
  series.sequencedInterpolation = true;
  
  // Make it stacked
  series.stacked = true;
  
  // Configure columns
  series.columns.template.width = am4core.percent(60);
  series.columns.template.tooltipText = "[bold]{name}[/]\n[font-size:14px]{categoryX}: {valueY}";
  
  // Add label
  var labelBullet = series.bullets.push(new am4charts.LabelBullet());
  labelBullet.label.text = "{valueY}";
  labelBullet.locationY = 0.5;
  labelBullet.label.hideOversized = true;
  
  return series;
}

createSeries("europe", "Europe");
createSeries("namerica", "North America");
createSeries("asia", "Asia-Pacific");
createSeries("lamerica", "Latin America");
createSeries("meast", "Middle-East");
createSeries("africa", "Africa");

// Legend
chart.legend = new am4charts.Legend();

1 Answers1

0

A possible solution is to make the columns floating, not stacked. I gave a similar solution for the same problem in amcharts5; more information is given there on the concept of floating bars, which is not described in amcharts4 documentation.

The idea is essentially to give for each data point - represented by a column item (i.e., a colored rectangle) both the start (or base) corresponding to dataFields.openValueY (see IColumnSeriesDataFields) and the end (or top) corresponding to dataFields.valueY, and set those values in such a way that they appear in the sorted order and when one item ends the next starts.

var chart = am4core.create("chartdiv", am4charts.XYChart);

// Add data
chart.data = [{
    "year": "2016",
    "europe": 5.5,
    "namerica": 2.5,
    "asia": 2.1,
    "lamerica": 0.3,
    "meast": 0.2,
    "africa":4.1
}, {
    "year": "2017",
    "namerica": 2.7,
    "asia": 2.2,
    "lamerica": 0.3,
    "meast": 0.3,
    "europe": 4.6,
    "africa": 2.1
}, {
    "year": "2018",
    "europe": 3.8,
    "namerica": 2.9,
    "asia": 2.4,
    "lamerica": 0.3,
    "meast": 0.3,
    "africa": 3.1
}];

const dataEntriesSorted = chart.data.map(
    o => Object.entries(o).filter(([_, v]) => typeof v === "number")
        .sort(([_key1, v1], [_key2, v2]) => v2 - v1)
);
dataEntriesSorted.forEach(function(entries, i){
    let sum = 0;
    entries.forEach(function([key, val]){
        chart.data[i][key + '_start'] = sum; // the start of the bar
        chart.data[i][key + '_end'] = val + sum; // the end of the bar
        sum += chart.data[i][key];
    })
});
// Create axes
var categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.dataFields.category = "year";
categoryAxis.renderer.grid.template.location = 0;

var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.renderer.inside = true;
valueAxis.renderer.labels.template.disabled = true;
valueAxis.min = 0;

// Create series
function createSeries(field, name) {
    // Set up series
    var series = chart.series.push(new am4charts.ColumnSeries());
    series.name = name;
    series.dataFields.value = field;
    series.dataFields.valueY = field+'_end';
    series.dataFields.openValueY = field+'_start';
    series.dataFields.categoryX = "year";
    series.sequencedInterpolation = true;

    //series.stacked = true;
    series.clustered = false;

    // Configure columns
    series.columns.template.width = am4core.percent(60);
    series.columns.template.tooltipText = "[bold]{name}[/]\n[font-size:14px]{categoryX}: {value}";

    // Add label
    var labelBullet = series.bullets.push(new am4charts.LabelBullet());
    labelBullet.label.text = "{value}";
    labelBullet.locationY = 0.5;
    labelBullet.label.hideOversized = true;

    return series;
}

createSeries("europe", "Europe");
createSeries("namerica", "North America");
createSeries("asia", "Asia-Pacific");
createSeries("lamerica", "Latin America");
createSeries("meast", "Middle-East");
createSeries("africa", "Africa");

// Legend
chart.legend = new am4charts.Legend();
<div id="chartdiv" style="width: 400px;height: 400px"></div>
<script src="//cdn.amcharts.com/lib/4/core.js"></script>
<script src="//cdn.amcharts.com/lib/4/charts.js"></script>
kikon
  • 3,670
  • 3
  • 5
  • 20