2025, Dec 31 12:02

Перевёрнутые биты 0/1 в Plotly и pandas: причина и решение

График двоичного потока в Plotly и pandas переворачивает 0/1 из‑за строковых типов. Объясняем причину и фикс: приводим столбцы к числовым и получаем ось y.

При построении графика двоичного потока обычно ожидаешь, что 0 будет внизу оси y, а 1 — наверху. Однако иногда отдельные ряды оказываются перевёрнутыми: 1 рисуется внизу, а 0 — наверху. Это особенно сбивает с толку, когда так ведут себя лишь некоторые столбцы, а остальные выглядят правильно. Ниже — минимальный пример того, как такое происходит при работе с Plotly и pandas.

Постановка задачи

Процедура построения проста: на каждый столбец — по одному трейсу, отображаем серии ступенчатыми линиями. Для части столбцов визуализация переворачивается.

import plotly.graph_objects as go

# bits_df — DataFrame с двоичными значениями в каждом столбце
chart = go.Figure()

for series_name in bits_df.columns:
    chart.add_trace(
        go.Scatter(
            x=bits_df.index,
            y=bits_df[series_name],
            name=series_name,
            visible="legendonly",
            line_shape='hv')
    )

chart.update_layout(
    autosize=False,
    width=1550,
    height=800,
    xaxis_title=bits_df.index.name,
    yaxis_title="State",
    yaxis=dict(range=[0, 1])
)

chart.show()

Что на самом деле происходит

Проблема не в рендерере Plotly и не в настройках фигуры. Причина — в типах данных. В некоторых столбцах значения хранятся как текст, а не как числа. То есть вместо чисел 0 и 1 в строках лежат строки "0" и "1". Получив текст по оси y, Plotly трактует его как категории. Порядок категорий на оси y определяется порядком первых встреченных меток в каждом трейсе. Если первым значением в столбце окажется "1", эта метка может расположиться перед "0" в категориальном порядке, из‑за чего уровни бита визуально меняются местами. Столбцы с настоящими числовыми значениями строятся корректно, с ожидаемым поведением числовой оси.

Решение

Перед построением преобразуйте серии к числовым типам. Когда данные становятся числами, Plotly использует числовую ось y, и уровни бита будут стабильно отображаться: 0 — внизу, 1 — наверху, во всех столбцах.

import pandas as pd
import plotly.graph_objects as go

# Убедитесь, что все нужные столбцы имеют числовой тип
bits_num = bits_df.apply(pd.to_numeric)

chart = go.Figure()

for series_name in bits_num.columns:
    chart.add_trace(
        go.Scatter(
            x=bits_num.index,
            y=bits_num[series_name],
            name=series_name,
            visible="legendonly",
            line_shape='hv')
    )

chart.update_layout(
    autosize=False,
    width=1550,
    height=800,
    xaxis_title=bits_num.index.name,
    yaxis_title="State",
    yaxis=dict(range=[0, 1])
)

chart.show()

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

В бинарной телеметрии, при анализе протоколов и визуализации цифровых сигналов важно соблюдение привычного правила: более высокий логический уровень расположен выше по оси. Смешение типов данных (dtypes) внутри DataFrame может незаметно нарушить это допущение во время разведочного анализа и привести к неверной интерпретации переходов битов. Единообразные числовые типы исключают влияние категориального упорядочивания на задуманное представление.

Итоги

Перед построением двоичных данных в Plotly убедитесь, что столбцы не хранятся как текст. Преобразуйте их в числовые типы, чтобы получить корректную числовую ось y и предсказуемое расположение 0/1. Если делитесь проблемой для разбора, прикладывайте небольшой воспроизводимый пример данных, а не изображения — так поведение быстрее воспроизвести и проверить.