Как отсортировать сегменты в каждом столбце гистограммы с накоплением, чтобы наибольшее значение для каждой категории всегда было вверху?

Я пытаюсь создать гистограмму с помощью 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 был вверху.

Кто-нибудь знает, возможно ли это и как этого достичь?

Заранее спасибо.

Я пробовал искать в документации, но не могу найти какие-либо свойства, которые позволили бы мне изменить порядок сегментов.

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Возможное решение — предварительно обработать данные, отсортировать записи в структуре данных и сделать столбцы плавающими, а не сложенными.

Это означает установку начального значения 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>

Другие вопросы по теме