2025, Dec 03 03:01
Как построить теплокарту из polars в Plotly без pandas
Показываем, как строить теплокарты из tidy‑данных polars в Plotly без конвертации в pandas: вариант с px.imshow и graph_objects, советы по оси y и ориентации.
Тепловые карты естественно подходят для tidy‑данных, но на этапе построения графика часто приходится делать пивот и переключаться между библиотеками. Если у вас уже есть tidy/длинный DataFrame в polars и вы хотите нарисовать теплокарту без захода в pandas, есть два аккуратных варианта: передать в Plotly Express широкую таблицу из polars или отдать tidy‑столбцы напрямую в Plotly graph_objects. Оба подхода избавляют от кругового пути через pandas.
Постановка задачи
Предположим, вы начинаете с tidy‑DataFrame в polars и строите теплокарту, сначала делая пивот в широкую форму и конвертацию в pandas перед отрисовкой. Это работает, но шагов больше, чем нужно.
import plotly.express as px
import polars as pl
long_pl = pl.DataFrame(
{
"x": [10, 10, 10, 20, 20, 20, 30, 30, 30],
"y": [3, 4, 5, 3, 4, 5, 3, 4, 5],
"value": [5, 8, 2, 4, 10, 14, 10, 8, 9],
}
)
print(long_pl)
wide_pd = (
long_pl.pivot(index="x", on="y", values="value").to_pandas().set_index("x")
)
print(wide_pd)
chart = px.imshow(wide_pd)
chart.show()
Что происходит под капотом
Когда вы передаёте Plotly объект DataFrame, он воспринимает индекс pandas как ось y. В polars у DataFrame нет такого понятия индекса, поэтому нужно явно указать, что использовать в качестве подписей по y. Это единственное принципиальное отличие, и его легко учесть без конвертации в pandas.
Если бы Plotly действительно умел работать с данными polars нативно, я бы ожидал, что он справится с tidy‑DataFrame, то есть без необходимости пивота.
Ожидание оправдывается: можно либо передать в Plotly Express широкую таблицу из polars и явно указать y, либо отдать plotly.graph_objects tidy‑столбцы напрямую и позволить ему построить сетку.
Решение: широкая таблица polars напрямую в Plotly Express
Остаёмся в polars: делаем пивот в широкую форму в памяти и говорим Plotly, что брать для y. Из матрицы Z убираем столбец с метками.
import plotly.express as px
wide_pl = long_pl.pivot(index="x", on="y", values="value")
heat1 = px.imshow(wide_pl.drop("x"), y=wide_pl["x"]) # подписи по оси y берутся из прежнего индекса
heat1.show()
Получится та же визуальная раскладка, что и в варианте с pandas, только без конвертаций.
Решение: tidy‑DataFrame polars с plotly.graph_objects
Можно строить график прямо из tidy‑столбцов. Подход повторяет то, как это делается с pandas в tidy‑формате.
import plotly.graph_objects as go
heat2 = go.Figure(
go.Heatmap(
x=long_pl["y"],
y=long_pl["x"],
z=long_pl["value"],
)
)
# Выравниваем ориентацию под вариант с широкой таблицей
heat2.update_layout(yaxis_autorange="reversed")
heat2.show()
Альтернатива: tidy‑построение через Altair
Если вам ближе Altair, в polars есть пространство имён .plot, принимающее tidy‑данные. Результат — сопоставимая теплокарта.
import altair as alt
(
long_pl.plot.rect(
x="y:O",
y="x:O",
# используем палитру в духе Plotly; простое color="value:Q" тоже подойдёт
color=alt.Color("value:Q", scale=alt.Scale(scheme="plasma")),
)
.properties(width=500, height=400)
)
Зачем это важно
Оставаясь в polars от начала до конца, вы упрощаете конвейер и избегаете межбиблиотечных преобразований. Plotly может рисовать напрямую из данных polars — будь то широкая матрица с явными подписями по y или tidy‑столбцы через graph_objects. Это помогает сохранить tidy‑подход на всём пути и держит код визуализации рядом с шагами преобразования данных.
Выводы
Если вы уже сделали пивот в polars, передайте px.imshow широкую таблицу polars, исключите из Z столбец‑метку и явно укажите y. Если хотите остаться целиком в tidy‑виде, создайте go.Heatmap, подставив x, y и z из соответствующих столбцов polars, и инвертируйте ось y для той же ориентации. Оба варианта обходятся без конвертации в pandas и делают этап визуализации компактным.