Can I make it so the size row heights are editable in a plotly subplot?

Viewed 46

I have this plot-

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

fig = make_subplots(rows=3, cols=1, row_heights = [0.3, 0.3, 0.4])

fig.append_trace(go.Scatter(
    x=[3, 4, 5],
    y=[1000, 1100, 1200],
), row=1, col=1)

fig.append_trace(go.Scatter(
    x=[2, 3, 4],
    y=[100, 110, 120],
), row=2, col=1)

fig.append_trace(go.Scatter(
    x=[0, 1, 2],
    y=[10, 11, 12]
), row=3, col=1)


fig.update_layout(height=600, width=600, title_text="Stacked Subplots")
fig.show()

I want it so that someone using the dashboard can adjust the size of each of the subplots. If they want to see the second subplot really big, for example, they could do that. I have a version that works using custom buttons and passing along the values as an argument in the row_height field. I'm curious if there's a slider or some other way where the user could control the relative height of each of the subplots.

1 Answers

Generally you need callbacks for the user to specify arguments that modify the plot, but plotly-python does have buttons and dropdowns as you mentioned.

You can control subplots individually using a slider if you use plotly-dash and make each slider value an input to a function that updates the subplot row heights.

Since you mentioned that you wanted the sliders to specify relative height, I divided each slider value by the sum of all slider values. This means that if each slider has the same value, the subplots will all look the same. This is functional as long as you don't allow all sliders values to be set to 0, but this could be potentially confusing from a user's perspective (alternatively, you could make the slider values in absolute units like pixels).

from plotly.subplots import make_subplots
import plotly.graph_objects as go
from dash import Dash, dcc, html, Input, Output

app = Dash(__name__)

app.layout = html.Div([
    html.H4('Live adjustable graph-size'),
    html.P("Change figure heights:"),
    dcc.Slider(id='slider-1', min=0.1, max=1, step=0.1, value=0.3),
    dcc.Slider(id='slider-2', min=0.1, max=1, step=0.1, value=0.3),
    dcc.Slider(id='slider-3', min=0.1, max=1, step=0.1, value=0.4),
    dcc.Graph(id="graph"),
])

@app.callback(
    Output("graph", "figure"), 
    Input('slider-1', 'value'),
    Input('slider-2', 'value'),
    Input('slider-3', 'value'))
def resize_figure(height_1, height_2, height_3):

    ## calculate relative heights
    total_height = height_1 + height_2 + height_3
    relative_heights = [height / total_height for height in [height_1, height_2, height_3]]
    fig = make_subplots(rows=3, cols=1, row_heights = relative_heights)

    fig.append_trace(go.Scatter(
        x=[3, 4, 5],
        y=[1000, 1100, 1200],
    ), row=1, col=1)

    fig.append_trace(go.Scatter(
        x=[2, 3, 4],
        y=[100, 110, 120],
    ), row=2, col=1)

    fig.append_trace(go.Scatter(
        x=[0, 1, 2],
        y=[10, 11, 12]
    ), row=3, col=1)


    fig.update_layout(height=600, width=600, title_text="Stacked Subplots")

    return fig

app.run_server(debug=True)

enter image description here

Related