Why do Plotly / Dash mixed graph and table subplots break when hline or vline are added?

Viewed 281

This is a 5 x 3 subplot layout as follows:

    fig = make_subplots(rows=5, cols=3,
                        specs=[[{'secondary_y': True}, {'secondary_y': False}, {'type': 'table'}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}]],
                        shared_xaxes=True, shared_yaxes=True,
                        vertical_spacing=0.01, horizontal_spacing=0,
                        row_heights=[0.775, 0.15, 0.025, 0.025, 0.025], column_widths=[0.8, 0.1, 0.1])

We add subplots as follows:

fig.add_trace(go.Scatter(x= ... row=1, col=1)
fig.add_trace(go.Scatter(x= ... row=1, col=2)
fig.add_trace(go.Scatter(x= ... row=2, col=1)
fig.add_trace(go.Scatter(x= ... row=3, col=1)
fig.add_trace(go.Scatter(x= ... row=4, col=1)
fig.add_trace(go.Scatter(x= ... row=5, col=1)

At position row=1 col=3 we place a table.

fig.add_trace(go.Table(header=dict(line=dict(color='red'),
                              fill=dict(color='red')),
                       cells=dict(values=[df.A, df.B])),
              row=1, col=3)

This all works fine. But when we add an hline or vline to the top left graph...

        fig.add_vline(x=42, line_width=1, line_dash='dot', line_color='rgba(255, 165, 0, 0.3)', row=1, col=1)

Plotly throws and error:

_plotly_utils.exceptions.PlotlyKeyError: Invalid property specified for object of type plotly.graph_objs.Table: 'xaxis'

Did you mean "cells"?

This happens regardless of line orientation (h or v), or if the lines are limited to a single row and col or spanning all cols.

Am I doing something wrong with my specs or layout, or could this be a bug?

1 Answers

I'm not a developer of plotly. This does appear to be a bug in plotly.

  • Adding the Scatter() traces, adding the the go.Table() to subplots then adding vline() fails
  • Adding the Scatter() traces, adding the vline() then adding Table() subplot succeeds

Code below shows this in reproducible example, changing where table is created means it succeeds or fails. I'd suggest two ways forward

  1. raise a bug / issue against plotly and wait for it to be fixed
  2. use workaround to create contents in order that does work
import plotly.graph_objects as go
import pandas as pd
import numpy as np
from plotly.subplots import make_subplots

fig = make_subplots(rows=5, cols=3,
                        specs=[[{'secondary_y': True}, {'secondary_y': False}, {'type': 'table'}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}],
                               [{'secondary_y': False}, {'secondary_y': False}, {'secondary_y': False}]],
                        shared_xaxes=True, shared_yaxes=True,
                        vertical_spacing=0.01, horizontal_spacing=0,
                        row_heights=[0.775, 0.15, 0.025, 0.025, 0.025], column_widths=[0.8, 0.1, 0.1])
for r in range(5):
    for c in range(3):
        if r==0 and c==2:
            if False:
                df=pd.DataFrame({"X":np.linspace(0,10,5), "Y":np.random.uniform(2,4,5)})
                fig.add_trace(go.Table(header={"values":df.columns}, cells={"values":df.T.values}), row=r+1, col=c+1)
            else:
                pass
        else:
            fig.add_trace(go.Scatter(x=np.linspace(0,50,20), y=np.random.uniform(1,5,29)), row=r+1, col=c+1)
            
fig.add_vline(x=42, line_width=1, line_dash='dot', line_color='rgba(255, 165, 0, 0.3)', row=1, col=1)

# create table after the vline has been added
df=pd.DataFrame({"X":np.linspace(0,10,5), "Y":np.random.uniform(2,4,5)})
fig.add_trace(go.Table(header={"values":df.columns}, cells={"values":df.T.values}), row=1, col=3)
Related