2025, Oct 31 20:46

Окраска X‑групп в сгруппированной столбчатой диаграмме Plotly Express

Как окрасить каждую X‑группу в сгруппированной столбчатой диаграмме Plotly Express из wide‑form DataFrame: используем update_traces и marker_color, без палитры

Окрашиваем каждую группу по оси X в сгруппированной столбчатой диаграмме Plotly Express

При создании сгруппированных столбчатых диаграмм в Plotly Express из широких (wide-form) DataFrame часто хочется, чтобы каждая группа по оси X была окрашена в один цвет, а не раскрашивать по сериям. Простое решение вроде задания палитры обычно меняет цвет целых трейсов (столбцов) во всех группах — это не то, что нужно, если цель — «один цвет на группу».

Воспроизводим настройку

Ниже пример сгруппированной диаграммы на базе DataFrame 3×3. Попытка управлять цветами через дискретную последовательность применяется к каждому трейсу и приводит к одинаковому окрашиванию во всех группах.

import plotly.express as px
import pandas as pd
df_ph_levels = pd.DataFrame([[8.33, 8.36, 8.36], [8.21, 8.18, 8.21], [7.50, 7.56, 7.64]], index=["4 °C", "37 °C", "37 °C + 5 % CO<sub>2"])
plot_ph = px.bar(df_ph_levels, barmode="group", color_discrete_sequence=["black"]*3)
# Настройка оформления
plot_ph = plot_ph.update_layout(
    showlegend=False,
    xaxis_title_text=None,
    yaxis_title_text="pH",
    width=900,
    height=800,
    margin=dict(t=0, b=0, l=0, r=0),
    yaxis_range=(6.5, 8.6)
)
plot_ph

Что происходит и почему цвета не меняются по группам

При широком формате входных данных Plotly Express создает по одному трейсу на каждый столбец DataFrame. Параметр, который передает палитру (например, дискретная последовательность), управляет цветами именно трейсов. Поэтому вы можете перекрасить первый, второй или третий столбец по всей диаграмме или сделать всё одним цветом, но с его помощью нельзя напрямую задать разные цвета для каждой группы по оси X.

Решение: раскрашивание по позиции столбца через update_traces

Чтобы раскрашивать по группам, передайте массив цветов для столбцов внутри каждого трейса и уберите дискретную последовательность. Это делается вызовом update_traces с marker_color, которому передан список нужных цветов. Тогда каждый трейс будет использовать один и тот же цвет для каждой позиции столбца, и все столбцы в одной x‑группе окажутся одного цвета.

import plotly.express as px
import pandas as pd
df_ph_levels = pd.DataFrame([[8.33, 8.36, 8.36], [8.21, 8.18, 8.21], [7.50, 7.56, 7.64]], index=["4 °C", "37 °C", "37 °C + 5 % CO<sub>2"])
plot_ph = px.bar(df_ph_levels, barmode="group")
# Настройка оформления
plot_ph = plot_ph.update_layout(
    showlegend=False,
    xaxis_title_text=None,
    yaxis_title_text="pH",
    width=900,
    height=800,
    margin=dict(t=0, b=0, l=0, r=0),
    yaxis_range=(6.5, 8.6)
)
# Назначаем цвета для каждой группы по оси X
plot_ph.update_traces(marker_color=["#0C3B5D", "#EF3A4C", "#FCB94D"]) 
plot_ph.show()

Почему это важно

Выбор, кодируют ли цвета трейсы или группы, влияет на то, как читают диаграмму. Если нужно, чтобы каждая категория на оси X воспринималась как цельный блок, такой подход сохраняет ясное соответствие и избавляет от борьбы с палитрами, которые работают на уровне трейсов.

Вывод

Если дискретная палитра упорно перекрашивает целые серии вместо групп по оси X, перейдите на update_traces с marker_color и передайте нужные вам цвета для групп. Не сочетайте это с color_discrete_sequence, чтобы ничто не переопределяло ваши цвета для отдельных столбцов. Небольшое изменение дает точный контроль над раскраской сгруппированных столбцов и делает диаграмму более однозначной.

Статья основана на вопросе с StackOverflow от Václav Bočan и ответе strawdog.