How to make mixed statistical subplots

I have some dataset in csv files(3 at total) and need to represent it in differents ways. They are necessarily line charts, box plots and histogram with kde(kernel density estimation).

I know how to plot them individually, but to make it more convenient I need to merge them into a single output. After consulting the reference I did write some code but it didn’t run.

Is there a way to combine make_subplots() with figure_factory.create_distplot()?

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import numpy as np

y1 = np.random.randn(200) - 1
y2 = np.random.randn(200)
y3 = np.random.randn(200) + 1
x = np.linspace(0, 1, 200)

fig = make_subplots(
    rows=3, cols=2,
    column_widths=[0.6, 0.4],
    row_heights=[0.3, 0.6, 0.9],
    specs=[[{"type": "scatter"}, {"type": ["box","box","box"]}],
           [{"type": "scatter"}, {"type": ["histogram","histogram","histogram","scatter","scatter","scatter"], "rowspan": 2}],
           [{"type": "scatter"},            None           ]])

fig.add_trace(
    go.Scatter(x = x, 
                y = y1,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='rgb(0, 0, 0)',
                width=1),
                showlegend=False,
                ),
    row=1, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y2,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='rgb(246, 52, 16)',
                width=1),
                showlegend=False,
                ),
    row=2, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y3,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='rgb(16, 154, 246)',
                width=1),
                showlegend=False,
                ),
    row=3, col=1
)

fig.add_trace(go.Figure(data=[go.Box(x=y1), go.Box(x=y2), go.Box(x=y3)]),
    row=1, col=2
)

group_labels = ['Group 1', 'Group 2', 'Group 3']
hist_data = [y1, y2, y3]

fig.add_trace(
    ff.create_distplot(hist_data, group_labels,
                         bin_size=.02, show_rug=False),
    row=2, col=2
)

fig.show()

How can I plot these charts with an unique output.

P.S. the line charts need to be separated for better visualization.

@Gastyr

First, the subplot definition can be shortened like this:

fig = make_subplots(
    rows=3, cols=2,
    column_widths=[0.6, 0.4],
    row_heights=[0.3, 0.6, 0.9])

If fig is a figure created by make_subplots(), then fig.add_trace() can add only a single trace at a time, or in these lines of code:

fig.add_trace(go.Figure(data=[go.Box(x=y1), go.Box(x=y2), go.Box(x=y3)]),
    row=1, col=2
)

you added a figure.

ff.create_distplot() returns a go.Figure, too.

Hence to get the right plot of your subplots, replace your code for box plots and distplot, as follows:

boxfig= go.Figure(data=[go.Box(x=y1), go.Box(x=y2), go.Box(x=y3)])
for k in range(len(boxfig.data)):
     fig.add_trace(boxfig.data[k] , row=1, col=2)

group_labels = ['Group 1', 'Group 2', 'Group 3']
hist_data = [y1, y2, y3]

distplfig = ff.create_distplot(hist_data, group_labels,
                         bin_size=.02, show_rug=False)

for k in range(len(distplfig.data)):
    fig.add_trace(distplfig.data[k],
    row=2, col=2
)
1 Like

@empet

Thank you very much, you are a truly lifesaver!!

Just one more question, how can I remove the trace legends beside the boxplots(β€œtrace 3”, …)?

For replicate the scenery, just run the code below:

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.figure_factory as ff
import numpy as np

y1 = np.random.randn(200) - 1
y2 = np.random.randn(200)
y3 = np.random.randn(200) + 1
x = np.linspace(0, 1, 200)

colors = ['#3f3f3f', '#00bfff', '#ff7f00']

fig = make_subplots(
    rows=3, cols=2,
    column_widths=[0.55, 0.45],
    row_heights=[1., 1., 1.],
    specs=[[{"type": "scatter"}, {"type": "xy"}],
           [{"type": "scatter"}, {"type": "xy", "rowspan": 2}],
           [{"type": "scatter"},            None           ]])

fig.add_trace(
    go.Scatter(x = x, 
                y = y1,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#3f3f3f',
                width=1),
                showlegend=False,
                ),
    row=1, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y2,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#00bfff',
                width=1),
                showlegend=False,
                ),
    row=2, col=1
)

fig.add_trace(
    go.Scatter(x = x, 
                y = y3,
                hoverinfo = 'x+y',
                mode='lines',
                line=dict(color='#ff7f00',
                width=1),
                showlegend=False,
                ),
    row=3, col=1
)

boxfig= go.Figure(data=[go.Box(x=y3, showlegend=False, notched=True, marker_color="#ff7f00"),
                        go.Box(x=y2, showlegend=False, notched=True, marker_color="#00bfff"),
                        go.Box(x=y1, showlegend=False, notched=True, marker_color="#3f3f3f")])

for k in range(len(boxfig.data)):
     fig.add_trace(boxfig.data[k], row=1, col=2)

group_labels = ['Group 1', 'Group 2', 'Group 3']
hist_data = [y1, y2, y3]

distplfig = ff.create_distplot(hist_data, group_labels, colors=colors,
                         bin_size=.2, show_rug=False)

for k in range(len(distplfig.data)):
    fig.add_trace(distplfig.data[k],
    row=2, col=2
)
fig.update_layout(barmode='overlay')
fig.show()

@Gastyr Those strings are default trace names, assigned by plotly.js when you don’t define the trace name explicitly. To remove them,
just give them another name:

boxfig= go.Figure(data=[go.Box(x=y3, showlegend=False, notched=True, marker_color="#ff7f00", name='box1'),
                        go.Box(x=y2, showlegend=False, notched=True, marker_color="#00bfff", name='box2'),
                        go.Box(x=y1, showlegend=False, notched=True, marker_color="#3f3f3f", name='box3')])

It should be nice to assign to each one the same name=’’, to avoid displaying any string, but with the same name=’ ', the boxes are overlayed.

1 Like