Я новичок в использовании D3 и создал горизонтальную гистограмму с накоплением на основе https://observablehq.com/@d3/stacked-horizontal-bar-chart.
Это мой график:
В настоящее время я могу сортировать диаграмму по возрастанию и убыванию. Что мне нужно сделать сейчас, так это сначала отсортировать график в алфавитном порядке по метке оси Y, а затем по возрастанию по значению на оси X, и я не знаю, как это сделать.
Диаграмма должна выглядеть примерно так:
Где диаграмма сортируется сначала в алфавитном порядке по названию шкалы на оси Y, а затем по убыванию или возрастанию по значению на оси X.
Это код, который я использую для создания диаграммы и сортировки ее по возрастанию/убыванию:
chartGenerate = stackedBarChart(pandas,
{
x: d => d.value,
y: d => d.scale,
z: d => d.key,
yDomain: d3.groupSort(pandas,
D => d3.sum(D, d => (order === "ascending" ? -d.value : d.value)),
d => d.scale),
zDomain: key,
}
)
Где значение — это значение одной из полос внутри большой полосы по оси X, шкала — это метка по оси Y, а ключ — это массив:
var key = ["punnets_underweight", "punnets_overweight", "punnets_on_weight"]
Порядок — это состояние, которое изменяется между значениями «по возрастанию» и «по убыванию» при нажатии кнопки.
Можно ли как-то изменить функцию groupSort, чтобы она могла сортировать по 2 свойствам объекта? Возможно, я упустил много информации, потому что не знал, как сформулировать все в целом, но это суть моей проблемы.
Вы написали:
Что мне нужно сделать сейчас, так это сначала отсортировать график в алфавитном порядке по метке оси Y, а затем по возрастанию по значению на оси X.
Однако, если я правильно понимаю ваш пример, вы не хотите сортировать по полной метке y (поскольку это будет полностью сортировать yDomain), а только по первой части - возможно, только до Line ${n}
или что-то в этом роде. Затем вы хотите отсортировать внутри этих групп по размеру?
Я уверен, что это можно сделать с помощью d3.groupSort
, используя более общий компаратор в качестве второго аргумента. Однако иногда мне трудно найти это особое заклинание для более специализированных функций более высокого уровня. Это определенно можно сделать с помощью d3.group
, а затем d3.sort
.
Поскольку у меня нет доступа к вашим данным, я разветвил блокнот Observable, на который вы ссылались, и создал там пример. В примере я довольно произвольно разбил состояния на первую половину алфавита, а затем на вторую. Затем я отсортировал по населению в этих двух группах. Код там выглядит так:
// An Array of objects with {state, population} keys:
state_populations = Array.from(
d3.group(stateages, (o) => o.state).values()
).map((a) => ({
state: a[0].state,
population: d3.sum(a, (o) => o.population)
}));
/// The yDomain
yDomain = d3
.sort(
state_populations,
(s) => (s.state < "M" ? 1 : 0),
(s) => s.population
)
.map((s) => s.state)
Подробнее вы можете посмотреть в блокноте. Вот верхняя часть получившегося изображения: