Amcharts:具有多个系列的堆积柱

Amcharts: stacked columns with multiple series

我在一个图表中有多个系列,例如在这个代码笔中看到的:

let chart = am4core.create("chartdiv", am4charts.XYChart);
      chart.leftAxesContainer.layout = "vertical";
      chart.numberFormatter.numberFormat = '# €';

      chart.data = [
        {name: "2011\nLorient", transport: 56, stay: 200, costByNight: 29, costByKm: 14},
        {name: "2015\nPoitiers\nLa Rochelle", transport: 96, stay: 54, costByNight: 9, costByKm: 23},
        {name: "2016\nRoyaume-Uni", transport: 160, stay: 332, costByNight: 47, costByKm: 62},
        {name: "2016\nBiarritz", transport: 185, stay: 516, costByNight: 74, costByKm: 27},
        {name: "2017\nRoyaume-Uni", transport: 258, stay: 355, costByNight: 36, costByKm: 24},
        {name: "2018\nSingapour\nVietnam\nTaïwan", transport: 1020, stay: 622, costByNight: 41, costByKm: 8},
        {name: "2018\nVietnam", transport: 753, stay: 294, costByNight: 49, costByKm: 8},
        {name: "2019\nCanada", transport: 1074, stay: 342, costByNight: 38, costByKm: 13},
        {name: "2019\nLorient\nGroix", transport: 77, stay: 190, costByNight: 27, costByKm: 20}
      ];

      chart.padding(20, 5, 2, 5);

      // Cities/countries names
      let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
      categoryAxis.renderer.grid.template.location = 0;
      categoryAxis.dataFields.category = "name";
      categoryAxis.renderer.ticks.template.disabled = false;
      categoryAxis.renderer.minGridDistance = 1;
      categoryAxis.renderer.labels.template.wrap = true;
      categoryAxis.renderer.labels.template.maxWidth = 100;
      categoryAxis.renderer.labels.template.fontSize = ".75em";
      categoryAxis.renderer.labels.template.textAlign = "middle";

      /* FIRST CHART */

      // First Y axis
      let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
      valueAxis.tooltip.disabled = true;
      valueAxis.zIndex = 1;
      valueAxis.renderer.baseGrid.disabled = true;
      valueAxis.renderer.fontSize = "0.8em";

      // Transport
      let series = chart.series.push(new am4charts.ColumnSeries());
      series.name = "Transport";
      series.dataFields.valueY = "transport";
      series.dataFields.categoryX = "name";
      series.yAxis = valueAxis;
      // Configure columns
      series.columns.template.width = am4core.percent(100);
      series.columns.template.tooltipText = "[font-size:13px]Transport : {valueY}";
      series.columns.template.fillOpacity = .8;

      // Logement
      series = chart.series.push(new am4charts.ColumnSeries());
      series.name = "Logement";
      series.dataFields.valueY = "stay";
      series.dataFields.categoryX = "name";
      series.yAxis = valueAxis;
      // Make it stacked
      series.stacked = true;
      // Configure columns
      series.columns.template.width = am4core.percent(100);
      series.columns.template.tooltipText = "[font-size:13px]Logement : {valueY}";
      series.columns.template.fillOpacity = .8;

      /* SECOND CHART */

      let valueAxis2 = chart.yAxes.push(new am4charts.ValueAxis());
      valueAxis2.marginTop = 50;
      valueAxis2.tooltip.disabled = true;
      valueAxis2.renderer.baseGrid.disabled = true;
      valueAxis2.zIndex = 3;
      valueAxis2.renderer.fontSize = "0.8em";

      series = chart.series.push(new am4charts.ColumnSeries());
      series.name = "Prix par 200km";
      series.dataFields.valueY = "costByKm";
      series.dataFields.categoryX = "name";
      series.yAxis = valueAxis2;
      series.stacked = true;
      // Configure columns
      series.columns.template.width = am4core.percent(40);
      series.columns.template.tooltipText = "[font-size:13px]Prix pour 200km : {valueY}";
      series.columns.template.fillOpacity = .8;

      series = chart.series.push(new am4charts.ColumnSeries());
      series.name = "Prix par nuitée";
      series.dataFields.valueY = "costByNight";
      series.dataFields.categoryX = "name";
      series.yAxis = valueAxis2;
      // Configure columns
      series.columns.template.width = am4core.percent(40);
      series.columns.template.tooltipText = "[font-size:13px]Prix par nuit : {valueY}";
      series.columns.template.fillOpacity = .8;
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

#chartdiv {
  width: 100%;
  height: 350px;
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>

我想做但不知道怎么做的是: - 使顶部列获得两个相应底部列的宽度(如某种 colspan) - 使底部系列相反,具有某种对称性(我尝试过相反= true,但它让一切都破裂了) - 两个图表之间有共同的 x 轴

预期的结果是这样的: Expected result

你能帮助实现至少其中一个目标吗?谢谢!

您可以使用您正在使用的堆叠值轴方法从三个中获得两个。

列系列将始终为其他列保留 space,无论是否存在值,因此您无法强制顶部图表的列完全展开。一个解决方法是创建第二个不可见的类别轴(禁用标签和网格)并将底部系列'xAxis分配给第二个类别轴:

let categoryAxis2 = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis2.renderer.grid.template.location = 0;
categoryAxis2.dataFields.category = "name";
categoryAxis2.renderer.ticks.template.disabled = true;
categoryAxis2.renderer.minGridDistance = 1;
categoryAxis2.renderer.labels.template.disabled = true;

// ...
series.xAxis = categoryAxis2; //repeat for both bottom chart's series
// ...

这将使顶部图表的列扩展到全宽,因为其他列完全与不同的轴相关联。

要反转底部图表以从顶部停止,请在值轴的渲染器对象中将 inversed 设置为 true:

valueAxis2.renderer.inversed = true;

但是分类轴不能放在中间。

下面的演示:

let chart = am4core.create("chartdiv", am4charts.XYChart);
chart.leftAxesContainer.layout = "vertical";
chart.numberFormatter.numberFormat = '# €';

chart.data = [
  {name: "2011\nLorient", transport: 56, stay: 200, costByNight: 29, costByKm: 14},
  {name: "2015\nPoitiers\nLa Rochelle", transport: 96, stay: 54, costByNight: 9, costByKm: 23},
  {name: "2016\nRoyaume-Uni", transport: 160, stay: 332, costByNight: 47, costByKm: 62},
  {name: "2016\nBiarritz", transport: 185, stay: 516, costByNight: 74, costByKm: 27},
  {name: "2017\nRoyaume-Uni", transport: 258, stay: 355, costByNight: 36, costByKm: 24},
  {name: "2018\nSingapour\nVietnam\nTaïwan", transport: 1020, stay: 622, costByNight: 41, costByKm: 8},
  {name: "2018\nVietnam", transport: 753, stay: 294, costByNight: 49, costByKm: 8},
  {name: "2019\nCanada", transport: 1074, stay: 342, costByNight: 38, costByKm: 13},
  {name: "2019\nLorient\nGroix", transport: 77, stay: 190, costByNight: 27, costByKm: 20}
];

chart.padding(20, 5, 2, 5);

// Cities/countries names
let categoryAxis = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis.renderer.grid.template.location = 0;
categoryAxis.dataFields.category = "name";
categoryAxis.renderer.ticks.template.disabled = false;
categoryAxis.renderer.minGridDistance = 1;
categoryAxis.renderer.labels.template.wrap = true;
categoryAxis.renderer.labels.template.maxWidth = 100;
categoryAxis.renderer.labels.template.fontSize = ".75em";
categoryAxis.renderer.labels.template.textAlign = "middle";

/* FIRST CHART */

// First Y axis
let valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis.tooltip.disabled = true;
valueAxis.zIndex = 1;
valueAxis.renderer.baseGrid.disabled = true;
valueAxis.renderer.fontSize = "0.8em";

// Transport
let series = chart.series.push(new am4charts.ColumnSeries());
series.name = "Transport";
series.dataFields.valueY = "transport";
series.dataFields.categoryX = "name";
series.yAxis = valueAxis;
// Configure columns
series.columns.template.width = am4core.percent(100);
series.columns.template.tooltipText = "[font-size:13px]Transport : {valueY}";
series.columns.template.fillOpacity = .8;

// Logement
series = chart.series.push(new am4charts.ColumnSeries());
series.name = "Logement";
series.dataFields.valueY = "stay";
series.dataFields.categoryX = "name";
series.yAxis = valueAxis;
// Make it stacked
series.stacked = true;
// Configure columns
series.columns.template.width = am4core.percent(100);
series.columns.template.tooltipText = "[font-size:13px]Logement : {valueY}";
series.columns.template.fillOpacity = .8;

/* SECOND CHART */

let valueAxis2 = chart.yAxes.push(new am4charts.ValueAxis());
valueAxis2.marginTop = 50;
valueAxis2.renderer.inversed = true;
valueAxis2.tooltip.disabled = true;
valueAxis2.renderer.baseGrid.disabled = true;
valueAxis2.zIndex = 3;
valueAxis2.renderer.fontSize = "0.8em";

let categoryAxis2 = chart.xAxes.push(new am4charts.CategoryAxis());
categoryAxis2.renderer.grid.template.location = 0;
categoryAxis2.dataFields.category = "name";
categoryAxis2.renderer.ticks.template.disabled = true;
categoryAxis2.renderer.minGridDistance = 1;
categoryAxis2.renderer.labels.template.disabled = true;


series = chart.series.push(new am4charts.ColumnSeries());
series.name = "Prix par 200km";
series.dataFields.valueY = "costByKm";
series.dataFields.categoryX = "name";
series.yAxis = valueAxis2;
series.stacked = true;
// Configure columns
series.columns.template.width = am4core.percent(40);
series.columns.template.tooltipText = "[font-size:13px]Prix pour 200km : {valueY}";
series.columns.template.fillOpacity = .8;
series.xAxis = categoryAxis2;

series = chart.series.push(new am4charts.ColumnSeries());
series.name = "Prix par nuitée";
series.dataFields.valueY = "costByNight";
series.dataFields.categoryX = "name";
series.yAxis = valueAxis2;
series.xAxis = categoryAxis2;
// Configure columns
series.columns.template.width = am4core.percent(40);
series.columns.template.tooltipText = "[font-size:13px]Prix par nuit : {valueY}";
series.columns.template.fillOpacity = .8;
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

#chartdiv {
  width: 100%;
  height: 350px;
}
<script src="//www.amcharts.com/lib/4/core.js"></script>
<script src="//www.amcharts.com/lib/4/charts.js"></script>
<script src="//www.amcharts.com/lib/4/themes/animated.js"></script>
<div id="chartdiv"></div>