Custom Sized Subplots

I am a plotly newbie …
I would like to create a 3 subplot chart (3 rows, 1 col) with subplot_1 taller than the others.
I have followed the example on line for Custom Sized Subplots but subplot_1 overlaps the lower plots and some details are lost. Below is a snippet that is setting rowspans and an attached image of the chart it creates.

fig = tools.make_subplots(rows=3, cols=1,
                          specs=[
                                 [{'rowspan': 2}],
                                 [{'rowspan': 1}],
                                 [{'rowspan': 1}]
                                ],
                          print_grid=True,
                          shared_xaxes=True,
                          vertical_spacing=0.02
                         )

Hello Jimmy, may I kindly ask you if you find any solution?
Many thanks,
Vaclav

@vaclavku To avoid plots overlapping you have to insert ‘vertical_spacing=0.075’, in tools.make_subplots(), where the right amount of spacing is chosen by trial.

If you have two or more horizontally placed subplots, then set also ‘horizontal_spacing=0.05’.

Hello Empet,
many thanks for your hit, however it doesn’t seem to work anyway.
fig = tools.make_subplots(rows=5, cols=3,
specs=[[{‘rowspan’: 2, ‘colspan’: 2}, None,{‘rowspan’: 2}],
[None, None, None],
[{‘colspan’: 2}, None, {}],
[{‘rowspan’: 2, ‘colspan’: 2}, None, {‘rowspan’: 2}],
[None, None, None]],
print_grid=False,
vertical_spacing=0.075,
horizontal_spacing=0.05)

The picture is even worse:

Note: As the workaround, I’ve defined multiple charts in layout.

Have a nice day.:-))
Vaclav

Hi @vaclavku,

As long as I cannot see how you appended the traces to fig, I cannot tell you what is wrong with your code.
For me this one works:

fig = tools.make_subplots(rows=5, cols=3,
specs=[[{'rowspan': 2, 'colspan': 2}, None,{'rowspan': 2}],
       [None, None, None],
       [{'colspan': 2}, None, {}],
       [{'rowspan': 2, 'colspan': 2}, None, {'rowspan': 2}],
      [None, None, None]],
#print_grid=False,
vertical_spacing=0.075,
horizontal_spacing=0.08)
This is the format of your plot grid:
[ (1,1) x1,y1           -      ]  [ (1,3) x2,y2 ]
       |                |                |       
[ (3,1) x3,y3           -      ]  [ (3,3) x4,y4 ]
[ (4,1) x5,y5           -      ]  [ (4,3) x6,y6 ]
       |                |                |       

trace1 = go.Scatter(
           x=np.linspace(0, 2, 60),
           y=np.random.rand(60),
           mode='lines',
           line=dict(width=1, color='red')
           )
fig.append_trace(trace1, 1,1)
fig.append_trace(trace1, 1,3)
fig.append_trace(trace1, 3,1)
fig.append_trace(trace1, 3,3)
fig.append_trace(trace1, 4,1)
fig.append_trace(trace1, 4,3)
fig.layout.update(title="My global title",
                     height=600, width=900, showlegend=False, hovermode='closest')

This is the resulted fig:

Hello @empet,
thanks, I appreciate your inputs.
The first part of the callback is:
@app.callback(Output(‘my-graph’, ‘figure’),
[Input(‘asset_dropdown’, ‘value’),
Input(‘mi_dropdown’, ‘value’)])

def update_graph(asset_dropdown_value, mi_dropdown_value):
fig = tools.make_subplots(rows=5, cols=3,
specs=[[{‘rowspan’: 2, ‘colspan’: 2}, None,{‘rowspan’: 2}],
[None, None, None],
[{‘colspan’: 2}, None, {}],
[{‘rowspan’: 2, ‘colspan’: 2}, None, {‘rowspan’: 2}],
[None, None, None]],
vertical_spacing=0.075,
horizontal_spacing=0.05)
fig[‘layout’][‘xaxis1’] = dict(rangeslider = dict( visible = False ))
fig[‘layout’][‘xaxis2’] = dict(rangeslider = dict( visible = False ))
fig[‘layout’][‘yaxis1’] = dict(titlefont=dict(
size=12,
color=colors[‘textlight’]
),
tickfont=dict(
size=12,
color=colors[‘textlight’]
)
)
fig[‘layout’][‘yaxis2’] = dict(titlefont=dict(
size=12,
color=colors[‘textlight’]
),
tickfont=dict(
size=12,
color=colors[‘textlight’]
)
)
fig[‘layout’][‘yaxis3’] = dict(titlefont=dict(
size=12,
color=colors[‘textlight’]
),
tickfont=dict(
size=12,
color=colors[‘textlight’]
)
)
fig[‘layout’][‘yaxis4’] = dict(titlefont=dict(
size=12,
color=colors[‘textlight’]
),
tickfont=dict(
size=12,
color=colors[‘textlight’]
)
)
fig[‘layout’][‘yaxis5’] = dict(titlefont=dict(
size=12,
color=colors[‘textlight’]
),
tickfont=dict(
size=12,
color=colors[‘textlight’]
)
)
fig[‘layout’][‘legend’] = dict(
x=0.0,
y=1.0,
bgcolor=colors[‘background’],
bordercolor=colors[‘links’])

for item in assets_select['id'].loc[assets_select['name'] == asset_dropdown_value]:
    chosen_tic = item + '_daily'

asset = pd.read_sql(chosen_tic, conn)

trace_ohlc_all = go.Candlestick(x=asset['date'],
            open=asset['open'],
            high=asset['high'],
            low=asset['low'],
            close=asset['close'],
            opacity = 0.5,
            line = dict(width= 0.5),
            increasing=dict(line=dict(color= '#C46A62'), fillcolor='#18D23C'),
            decreasing=dict(line=dict(color= '#E42515'), fillcolor='#176F28')
            )

trace_ohlc_30d = go.Candlestick(x=asset['date'],
            open=asset['open'],
            high=asset['high'],
            low=asset['low'],
            close=asset['close'],
            opacity = 0.5,
            line = dict(width= 0.5),
            increasing=dict(line=dict(color= '#C46A62'), fillcolor='#18D23C'),
            decreasing=dict(line=dict(color= '#E42515'), fillcolor='#176F28')
            )

fig.append_trace(trace_ohlc_all,1,1)
fig.append_trace(trace_ohlc_all,1,3)

the rest with the same logic:
fig.append_trace(mi_trace,4,1)
fig.append_trace(mi_trace,4,3)

fig['layout']['yaxis1'].update(title='OHLC')
fig['layout']['yaxis2'].update(title='OHLC2')
fig['layout']['yaxis3'].update(title='Volume')
fig['layout']['yaxis4'].update(title='MI')
fig['layout']['yaxis5'].update(title='MI2')
fig['layout'].update(height=1000, width=1600)

return fig

if name == ‘main’:
app.run_server(debug=True, port = 10013)

Cheers,
Vaclav

@vaclavku, I identified the issue of your code.

When you define:

fig = tools.make_subplots(rows=5, cols=3,
                      specs=[[{‘rowspan’: 2, ‘colspan’: 2}, None,{‘rowspan’: 2}],
                             [None, None, None],
                            [{‘colspan’: 2}, None, {}],
                            [{‘rowspan’: 2, ‘colspan’: 2}, None, {‘rowspan’: 2}],
                            [None, None, None]],
                             vertical_spacing=0.075,
                             horizontal_spacing=0.05)    

fig.layout #inspect fig.layout

Layout({
    'xaxis': {'anchor': 'y', 'domain': [0.0, 0.6399999999999999]},
    'xaxis2': {'anchor': 'y2', 'domain': [0.72, 1.0]},
    'xaxis3': {'anchor': 'y3', 'domain': [0.0, 0.6399999999999999]},
    'xaxis4': {'anchor': 'y4', 'domain': [0.72, 1.0]},
    'xaxis5': {'anchor': 'y5', 'domain': [0.0, 0.6399999999999999]},
    'xaxis6': {'anchor': 'y6', 'domain': [0.72, 1.0]},
    'yaxis': {'anchor': 'x', 'domain': [0.6449999999999999, 0.9999999999999999]},
    'yaxis2': {'anchor': 'x2', 'domain': [0.6449999999999999, 0.9999999999999999]},
    'yaxis3': {'anchor': 'x3', 'domain': [0.42999999999999994, 0.57]},
    'yaxis4': {'anchor': 'x4', 'domain': [0.42999999999999994, 0.57]},
    'yaxis5': {'anchor': 'x5', 'domain': [0.0, 0.355]},
    'yaxis6': {'anchor': 'x6', 'domain': [0.0, 0.355]}
})

the layout is set up and assignments like these:

fig['layout']['xaxis1'] = dict(rangeslider = dict( visible = False ))
fig['layout']['xaxis2' ] = dict(rangeslider = dict( visible = False ))

redefine the fig['layout']['xaxis1'], and fig['layout']['xaxis2'], and your initial settings are lost:

fig.layout

Layout({
    'xaxis': {'rangeslider': {'visible': False}},
    'xaxis2': {'rangeslider': {'visible': False}},
    'xaxis3': {'anchor': 'y3', 'domain': [0.0, 0.6399999999999999]},
    'xaxis4': {'anchor': 'y4', 'domain': [0.72, 1.0]},
    'xaxis5': {'anchor': 'y5', 'domain': [0.0, 0.6399999999999999]},
    'xaxis6': {'anchor': 'y6', 'domain': [0.72, 1.0]},
    'yaxis': {'anchor': 'x', 'domain': [0.6449999999999999, 0.9999999999999999]},
    'yaxis2': {'anchor': 'x2', 'domain': [0.6449999999999999, 0.9999999999999999]},
    'yaxis3': {'anchor': 'x3', 'domain': [0.42999999999999994, 0.57]},
    'yaxis4': {'anchor': 'x4', 'domain': [0.42999999999999994, 0.57]},
    'yaxis5': {'anchor': 'x5', 'domain': [0.0, 0.355]},
    'yaxis6': {'anchor': 'x6', 'domain': [0.0, 0.355]}
})

You should make updates, not assignments:

fig['layout']['xaxis1'].update(rangeslider = dict( visible = False ))   
fig['layout']['xaxis2'].update(rangeslider = dict( visible = False ))

Now `

fig.layout.xaxis1   # displays:

layout.XAxis({
    'anchor': 'y', 'domain': [0.0, 0.6399999999999999], 'rangeslider': {'visible': False}
})

i.e. the initial setting were preserved.

1 Like

Hi @empet,
really works. It’s like a true detective job and you saved my life (for the moment).
Just curiousity point: When I try to solve it with the multiple charts, I’ve met following issue:

  • I’ve one input (dropdown) and multiple outputs (decorators/plots).
  • The input is about the ID of the an asset. The date is being retrieved from the MySQL database (individual tables).

The point is that the solution works only if one request is applied. If multiple outputs are expected, the applications stops (often) with no reasons.
Do you have any idea what might goes wrong?

Cheers,
Vaclav

Please address this question under dash category on this forum. I have no experience with dash