Я пытаюсь создать гистограмму с помощью AmCharts 5, где сегменты для каждого столбца отсортированы от наименьшего к наибольшему, так что самый большой сегмент всегда помещается вверху столбца.
Мой код диаграммы пока выглядит так:
// Get chart div by id
var chartDiv = document.getElementById(selector);
const data = JSON.parse(chartDiv.getAttribute('data-chart'));
const fontSize = 12;
const markerSize = 12;
var root = am5.Root.new(selector);
var chart = root.container.children.push(
am5xy.XYChart.new(root, {
panY: false,
layout: root.verticalLayout,
dy: 10,
})
);
// Create X-axis
let xAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "week_ending_date",
renderer: am5xy.AxisRendererX.new(root, {})
})
);
let xRenderer = xAxis.get("renderer");
xRenderer.labels.template.setAll({
fontSize: fontSize
});
xAxis.data.setAll(data);
// Create Y-Axis
var yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {}),
})
);
let yRenderer = yAxis.get("renderer");
yRenderer.labels.template.setAll({
fontSize: fontSize
});
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
function makeSeries(name, fieldName, colorHex) {
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
stacked: true,
xAxis: xAxis,
yAxis: yAxis,
baseAxis: xAxis,
valueYField: fieldName,
categoryXField: "week_ending_date",
fill: colorHex,
}));
series.columns.template.setAll({
tooltipText: "{name} - {valueY}",
tooltipY: am5.percent(90)
});
series.data.setAll(data);
series.bullets.push(function() {
return am5.Bullet.new(root, {
sprite: am5.Label.new(root, {
text: "{valueX}",
fill: root.interfaceColors.get("alternativeText"),
centerY: am5.p50,
centerX: am5.p50,
populateText: true,
fontSize: 12,
})
});
});
legend.data.push(series);
}
// Add series for each site in the data
// Get all site names
let sites = Object.keys(data[0])
// Remove first value (week_ending_date)
sites.shift()
sites.forEach((site, index) => {
makeSeries(site, site, COLOR_SCHEME[index]);
})
И мои данные выглядят так:
[
{
"week_ending_date": "2022-10-02",
"site A": 100,
"site B": 150,
"site C": 200,
},
{
"week_ending_date": "2022-10-09",
"site A": 400,
"site B": 150,
"site C": 50,
},
...
Итак, в моем первом столбце я хочу, чтобы сайт C отображался вверху, а во втором столбце я хочу, чтобы сайт A был вверху.
Кто-нибудь знает, возможно ли это и как этого достичь?
Заранее спасибо.
Я пробовал искать в документации, но не могу найти какие-либо свойства, которые позволили бы мне изменить порядок сегментов.
Возможное решение — предварительно обработать данные, отсортировать записи в структуре данных и сделать столбцы плавающими, а не сложенными.
Это означает установку начального значения y и конечного значения y для каждого столбца (то есть для каждой точки данных); это позволяет нам расположить отсортированные столбцы по порядку: конец самого короткого будет началом второго самого короткого, а конец второго самого короткого будет началом самого длинного такта.
Вот фрагмент кода, основанный на вашем коде, который реализует этот метод:
//var chartDiv = document.getElementById(selector);
//const data = JSON.parse(chartDiv.getAttribute('data-chart'));
const data = [
{
"week_ending_date": "2022-10-02",
"site A": 100,
"site B": 150,
"site C": 200,
},
{
"week_ending_date": "2022-10-09",
"site A": 400,
"site B": 150,
"site C": 50,
},
{
"week_ending_date": "2022-10-16",
"site A": 200,
"site B": 150,
"site C": 200,
},
{
"week_ending_date": "2022-10-23",
"site A": 120,
"site B": 150,
"site C": 200,
}];
const fontSize = 12;
//const markerSize = 12;
var root = am5.Root.new(selector);
var chart = root.container.children.push(
am5xy.XYChart.new(root, {
panY: false,
layout: root.verticalLayout,
dy: 10,
})
);
// Create X-axis
let xAxis = chart.xAxes.push(
am5xy.CategoryAxis.new(root, {
categoryField: "week_ending_date",
renderer: am5xy.AxisRendererX.new(root, {})
})
);
let xRenderer = xAxis.get("renderer");
xRenderer.labels.template.setAll({
fontSize: fontSize
});
xAxis.data.setAll(data);
// Create Y-Axis
var yAxis = chart.yAxes.push(
am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {}),
})
);
let yRenderer = yAxis.get("renderer");
yRenderer.labels.template.setAll({
fontSize: fontSize
});
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
function makeSeries(name, fieldName, colorHex) {
var series = chart.series.push(am5xy.ColumnSeries.new(root, {
name: name,
//stacked: false, // default
clustered: false,
xAxis: xAxis,
yAxis: yAxis,
baseAxis: xAxis,
trueValue: data,
valueYField: fieldName+'_end',
openValueYField: fieldName+'_start',
categoryXField: "week_ending_date",
fill: colorHex,
}));
series.columns.template.setAll({
tooltipText: "{name} - {"+fieldName+"}",
tooltipY: am5.percent(90),
});
series.data.setAll(data);
series.bullets.push(function() {
return am5.Bullet.new(root, {
sprite: am5.Label.new(root, {
text: "{valueX}",
fill: root.interfaceColors.get("alternativeText"),
centerY: am5.p50,
centerX: am5.p50,
populateText: true,
fontSize: 12,
})
});
});
const legend = chart.children.push(am5.Legend.new(root, {}));
legend.data.push(series);
}
// Get all site names
let sites = Object.keys(data[0])
// Remove first value (week_ending_date)
sites.shift()
// preprocess data
const dataEntriesSorted = data.map(
o => Object.entries(o).filter(([_, v]) => typeof v === "number").
sort(([_key1, v1], [_key2, v2]) => v1 - v2)
);
dataEntriesSorted.forEach(function(entries, i){
let sum = 0;
entries.forEach(function([key, val]){
data[i][key+'_start'] = sum; // the start of the bar
data[i][key+'_end'] = val + sum; // the end of the bar
sum += data[i][key];
})
});
// Add series for each site in the data
sites.forEach((site, index) => {
makeSeries(site, site, chart.get("colors").next());
});
<div id = "selector" style = "width: 400px;height: 400px"></div>
<script src = "https://cdn.amcharts.com/lib/5/index.js"></script>
<script src = "https://cdn.amcharts.com/lib/5/xy.js"></script>