2025, Nov 01 13:47

Почему при использовании Plotly с ipywidgets в Jupyter отображается только последний график и как это исправить

Разбираем, почему при выводе Plotly в ipywidgets/Output в Jupyter остаётся только последний график. Покажем воспроизведение и рабочее решение: единый display.

При совмещении Plotly Express с контейнерами Output из ipywidgets в Jupyter нередко случается неожиданность: отображается только последний график, а предыдущие пропадают. Сетка и размеры виджетов выглядят корректно, но три фигуры просто не рендерятся. Причина не в сетке, а в способе вывода фигур.

Как воспроизвести проблему

В примере ниже создаются четыре графика Plotly, они помещаются в области Output и располагаются в GridspecLayout. Тем не менее виден только последний график.

import plotly.express as px
import ipywidgets as widgets
from ipywidgets import GridspecLayout, Layout, Output

panel_dims = Layout(
    width='100%',
    height='300px',
    border='1px solid gray',
    overflow='auto'
)

cell_bar = Output(layout=panel_dims)
cell_line = Output(layout=panel_dims)
cell_dot = Output(layout=panel_dims)
cell_bins = Output(layout=panel_dims)

iris_tbl = px.data.iris()
with cell_dot:
    chart = px.scatter(iris_tbl, x='sepal_width', y='sepal_length', color='species')
    chart.show()

tips_tbl = px.data.tips()
with cell_bar:
    chart = px.bar(tips_tbl, x='day', y='total_bill', color='sex', barmode='group')
    chart.show()

canada_tbl = px.data.gapminder().query("country == 'Canada'")
with cell_line:
    chart = px.line(canada_tbl, x='year', y='gdpPercap', title='GDP per Capita - Canada')
    chart.show()

with cell_bins:
    chart = px.histogram(tips_tbl, x='total_bill', nbins=30, color='sex')
    chart.show()

mesh = GridspecLayout(
    4, 1,
    layout=Layout(
        width='100%',
        height='auto',
        grid_gap='10px'
    )
)

mesh[0, 0] = cell_line
mesh[1, 0] = cell_bar
mesh[2, 0] = cell_dot
mesh[3, 0] = cell_bins

mesh

Почему первые три графика пропадают

Все дело в способе отображения каждой фигуры. Последовательные вызовы show для каждого графика приводят к тому, что в итоге в выводе остается только последний. Если таким же образом использовать display для отдельной фигуры, результат будет тот же. Уберете show у последней — отобразится предыдущая; уберете у предыдущей — проявится та, что была до нее, и так далее. Проще говоря, самый поздний вызов перекрывает предыдущие.

Исправление, которое стабильно работает

Создавайте каждую фигуру Plotly, не вызывая show или display внутри контекстов Output, а затем отобразите все фигуры одной общей командой. Так все четыре графика рендерятся одновременно. Этот подход работает даже без сетки.

import plotly.express as px
import ipywidgets as widgets
from ipywidgets import GridspecLayout, Layout, Output

panel_box = Layout(
    width='100%',
    height='300px',
    border='1px solid gray',
    overflow='auto'
)

box_bar = Output(layout=panel_box)
box_line = Output(layout=panel_box)
box_scatter = Output(layout=panel_box)
box_hist = Output(layout=panel_box)

iris_data = px.data.iris()
with box_scatter:
    fig_a = px.scatter(iris_data, x='sepal_width', y='sepal_length', color='species')

bill_data = px.data.tips()
with box_bar:
    fig_b = px.bar(bill_data, x='day', y='total_bill', color='sex', barmode='group')

ca_data = px.data.gapminder().query("country == 'Canada'")
with box_line:
    fig_c = px.line(ca_data, x='year', y='gdpPercap', title='GDP per Capita - Canada')

with box_hist:
    fig_d = px.histogram(bill_data, x='total_bill', nbins=30, color='sex')

layout_grid = GridspecLayout(
    4, 1,
    layout=Layout(
        width='100%',
        height='auto',
        grid_gap='10px'
    )
)

layout_grid[0, 0] = box_line
layout_grid[1, 0] = box_bar
layout_grid[2, 0] = box_scatter
layout_grid[3, 0] = box_hist

# layout_grid

display(fig_a, fig_b, fig_c, fig_d)

Почему это важно для ваших ноутбуков

При создании дашбордов или аналитических отчетов в Jupyter с Plotly и ipywidgets легко предположить, что последовательный рендеринг фигур в разных выходах даст несколько видимых графиков. На практике последний вызов отображения может всё перетянуть на себя. Понимание того, что show или display для одной фигуры способны скрыть ранее отрендеренные графики, избавит от напрасных поисков проблем в сетке или размерах виджетов, которые здесь ни при чем.

Итоги

Если несколько фигур Plotly не показываются и остается только последний график, не вызывайте show или одиночный display многократно. Сформируйте фигуры, сохраните их в переменных и выведите одной общей командой display. Это простое изменение гарантированно отображает все четыре графика — с сеткой виджетов или без нее.

Статья основана на вопросе со StackOverflow от Mohamad Osama и ответе furas.