2025, Nov 01 19:16
Сортировка оси X с mark_errorbar в Altair: решение через EncodingSortField
Почему сортировка оси X в многослойных диаграммах Altair с mark_errorbar сбивается и как это исправить. Показываем рабочий прием с EncodingSortField.
Слоистые диаграммы в Altair — один из базовых приемов, когда нужно объединить столбцы с интервалами или полосами неопределенности. Частая задача — упорядочить ось X по количественному показателю на оси Y. Для столбцов и правил это просто, но с появлением интервалов ошибок начинается путаница: та же сортировка неожиданно возвращается к алфавитному порядку.
Воспроизводим проблему
Пример ниже иллюстрирует столбчатую диаграмму, поверх которой накладываются либо линии-правила, либо интервалы ошибок. Сортировка оси X по метрике Y работает с правилами, но не с интервалами ошибок — хотя каждый слой по отдельности сортируется верно.
import polars as pl
import altair as alt
data_tbl = pl.DataFrame({
"label": ["A", "B", "C", "D"],
"avg": [1.2, 2.5, 0.9, 3.1],
"lo": [1.0, 2.2, 0.85, 2.8],
"hi": [1.4, 2.8, 0.95, 3.4]
})
base_cols = alt.Chart(data_tbl).mark_bar().encode(
x=alt.X("label:N").sort("-y"),
y=alt.Y("avg:Q")
)
err_overlay = base_cols.mark_errorbar().encode(
y="lo:Q",
y2="hi:Q"
)
rule_overlay = base_cols.mark_rule().encode(
y="lo:Q",
y2="hi:Q"
)
# Не сортируется
base_cols + err_overlay
# Сортируется
base_cols + rule_overlay
Каждый слой по отдельности сортируется корректно. В комбинировании «столбцы + интервалы ошибок» ось X возвращается к алфавитному порядку, тогда как «столбцы + правила» сохраняют сортировку по Y.
Что происходит
Поведение сводится к способу задания сортировки. Короткая строковая запись сортировки по X с помощью «-y» при наложении слоёв с интервальными ошибками может игнорироваться, тогда как при наложении с правилами она работает. На практике это означает, что неявная сортировка по каналу Y для mark_errorbar в многослойной диаграмме соблюдается не всегда. Явная сортировка по полю устраняет несогласованность.
Как исправить
Задайте сортировку через EncodingSortField на канале X и укажите поле с количественной метрикой, которое должно определять порядок. Тогда порядок сохранится и при наложении интервалов ошибок.
import polars as pl
import altair as alt
data_tbl = pl.DataFrame({
"label": ["A", "B", "C", "D"],
"avg": [1.2, 2.5, 0.9, 3.1],
"lo": [1.0, 2.2, 0.85, 2.8],
"hi": [1.4, 2.8, 0.95, 3.4]
})
base_cols = alt.Chart(data_tbl).mark_bar().encode(
x=alt.X("label:N").sort(alt.EncodingSortField(field="avg", op="min")),
y=alt.Y("avg:Q")
)
err_overlay = base_cols.mark_errorbar().encode(
y="lo:Q",
y2="hi:Q"
)
# Теперь сортируется правильно
base_cols + err_overlay
Подробнее: issue на GitHub.
Почему это важно
Порядок на осях — не косметика. От него зависит, как считываются ранжирования, экстремумы и общие закономерности. При добавлении неопределенности через mark_errorbar сокращённая запись сортировки может незаметно скатиться к алфавитному порядку, что мешает сравнению. Явный EncodingSortField привязывает порядок к нужной метрике и делает диаграмму устойчивой к тонкостям наложения слоёв.
Выводы
Если нужно отсортировать ось X в многослойной диаграмме по величине, зависящей от Y, и вы добавляете интервалы ошибок, отдавайте предпочтение явной сортировке через EncodingSortField на канале X. Укажите количественное поле, определяющее высоту столбцов, и задайте агрегацию, соответствующую замыслу. Эта маленькая правка предотвращает неожиданную перестановку и сохраняет согласованность визуализаций.