'plotly: add box plot as subplot

I'm attempting to create a visualization where a pie chart appears on top, and a box plot appears below. I'm using the plotly library.

I tried using this code:

import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

fig = make_subplots(
    rows=2, cols=1,
    specs=[[{'type':'pie'}], [{'type':'box'}]],
)

# pie chart
pie = go.Pie(values=[1, 2, 3, 4, 5], labels=['a', 'b', 'a', 'a', 'c'], sort=False)

# box plot
import numpy as np
np.random.seed(1)

y0 = [10, 1, 2, 3, 1, 5, 8, 2]
y1 = [10, 1, 2, 3, 1, 5, 8, 2]

box = go.Figure()
box.add_trace(go.Box(y=y0))
box.add_trace(go.Box(y=y1))

# add pie chart and box plot to figure
fig.add_trace(pie, row=1, col=1)
fig.add_trace(box, row=2, col=1)
fig.update_traces(textposition='inside', textinfo='percent+label')

fig.show()

However, I'm encountering this error:

Invalid element(s) received for the 'data' property of
        Invalid elements include: [Figure({
    'data': [{'type': 'box', 'y': [10, 1, 2, 3, 1, 5, 8, 2]}, {'type': 'box', 'y': [10, 1, 2, 3, 1, 5, 8, 2]}],
    'layout': {'template': '...'}
})]


Solution 1:[1]

There are two errors in your code

  1. box is created as a figure. add_trace() adds a trace not a figure. Changed to loop through traces in box figure
  2. update_traces() is updating attributes that don't exist in a Box trace. Changed to use for_each_trace() and update attribute that are valid for trace type

full code

import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots

fig = make_subplots(
    rows=2,
    cols=1,
    specs=[[{"type": "pie"}], [{"type": "box"}]],
)

# pie chart
pie = go.Pie(values=[1, 2, 3, 4, 5], labels=["a", "b", "a", "a", "c"], sort=False)

# box plot
import numpy as np

np.random.seed(1)

y0 = [10, 1, 2, 3, 1, 5, 8, 2]
y1 = [10, 1, 2, 3, 1, 5, 8, 2]

box = go.Figure()
box.add_trace(go.Box(y=y0))
box.add_trace(go.Box(y=y1))

# add pie chart and box plot to figure
fig.add_trace(pie, row=1, col=1)
# fig.add_trace(box, row=2, col=1)
for t in box.data:
    fig.add_trace(t, row=2, col=1)
# fig.update_traces(textposition='inside', textinfo='percent+label')
fig.for_each_trace(
    lambda t: t.update(textposition="inside", textinfo="percent+label")
    if isinstance(t, go.Pie)
    else t
)


fig.show()

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rob Raymond