How to pass figure layout info into subplot

In Python,I am trying to make two subplots on a 1 x 2 grid. I define the subplot array with make_subplots; call this figure fig. The (1, 1) plot, fig1, is a surface plot and the (1, 2) plot, fig2, is a heatmap. After modifying the layouts of fig1 and fig2 to get the desired display, I am able to display them separately without problems. When I combine their traces into fig and display fig, the surface and heatmap display side-by-side as expected, but without the modified layouts; they appear with all the default layouts.

How do I pass the layout information from fig1 and fig2 into fig? I am frustrated that there isnโ€™t a simple way to do this.

Here is working example, with more layout changes to fig1 and fig 2 than are necessary to show the problem, so sorry for the lengthy paste.

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px
import numpy as np
from pprint import pprint

x = np.linspace(0.0, 3.0, 4)
y = np.linspace(0.0, 3.0, 4)
z = np.array([[1.1, 2.2, 3.3, 4.4],
             [3.2, 5.3, 6.2, 2.3],
             [1.3, 5.2, 3.2, 6.2],
             [2.1, 4.6, 3.6, 4.2]])

# Set up subplots.
fig = make_subplots(rows=1, cols=2,
                    # specs=[[{'is_3d': True}, {'is_3d': False}]],
                    specs=[[{'type': 'surface'}, {'type': 'image'}]],
                    subplot_titles=['Perspective plot',
                                    'Intensity plot'])
fig.update_layout(height=700, width=1200, title_text="Side By Side Subplots")

# Surface plot from z data.
lighting_effects = dict(ambient=0.2, roughness=0.5,
                        diffuse=0.8, fresnel=0.2, specular=0.05)
trace1 = go.Surface(z=z, x=x, y=y, colorscale='gray_r', lighting=lighting_effects)
fig1 = go.Figure(data=[trace1])
fig1.layout.scene.camera.projection.type = "orthographic" # or perspective which is default
fig1.update_layout(title='Radar Magnitude', autosize=False,
    width=650, height=650,
    margin=dict(l=20, r=20, b=20, t=20),
    scene=dict(xaxis_title='x (range)', yaxis_title='y (crossrange', zaxis_title='Magnitude'))
fig1.update_layout(scene=dict(
    xaxis=dict(ticks='outside', ticklen=10),
    yaxis=dict(ticks='outside', ticklen=10),
    zaxis=dict(ticks='outside', ticklen=10)), overwrite=False)
fig1.update_layout(coloraxis_showscale=False) # Doesn't work for surface, only imshow.
fig1.update_layout(scene=dict(
    xaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2),
    yaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2),
    zaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2),)
)
fig1.update_traces(showscale=False)
fig1.show() # Displays single plot with modified layout.

# Gray-scale heatmap from z data.
Axis_Labels = dict(x = "Range", y = "Crossrange")
fig2 = px.imshow(img=z, x=x, y=y, color_continuous_scale='gray_r', 
                origin="lower",
                labels = Axis_Labels)
fig2.update_layout(coloraxis_showscale=False) # No color bar
fig2.update_xaxes(ticks="outside", ticklen=10)
fig2.update_yaxes(ticks="outside", ticklen=10)
fig2.update_xaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True))
fig2.update_yaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True))
fig2.update_xaxes(showline=True, linewidth=2, linecolor='black', mirror=True) # zero axis, mirror
fig2.update_yaxes(showline=True, linewidth=2, linecolor='black', mirror=True)
fig2.update_xaxes(showgrid=True, gridwidth=2, gridcolor='Black') # Doesn't
fig2.update_yaxes(showgrid=True, gridwidth=2, gridcolor='Black') # work
fig2.update_layout(width=600, height=600, title="Radar Magnitude",
                  margin=dict(l=10, r=10, b=10, t=30))
fig2.show()  # Displays single plot with modified layout.

fig.add_trace(fig1.data[0], 1, 1)
fig.add_trace(fig2.data[0], 1, 2)
fig.show() # Displays side-by-side plots with with _original_ layout, not mofidied.

The first subplot updates the contents of the 3D graph with fig.update_scenes(); the second uses a heatmap of the graph object.
I am not sure I have covered all your graph requests, so if there is anything missing, please feel free to add or modify using the same technique.

import plotly.graph_objects as go
from plotly.subplots import make_subplots
import plotly.express as px
import numpy as np
from pprint import pprint

x = np.linspace(0.0, 3.0, 4)
y = np.linspace(0.0, 3.0, 4)
z = np.array([[1.1, 2.2, 3.3, 4.4],
             [3.2, 5.3, 6.2, 2.3],
             [1.3, 5.2, 3.2, 6.2],
             [2.1, 4.6, 3.6, 4.2]])

# Set up subplots.
fig = make_subplots(rows=1, cols=2,
                    # specs=[[{'is_3d': True}, {'is_3d': False}]],
                    specs=[[{'type': 'surface'}, {'type': 'image'}]],
                    subplot_titles=['Perspective plot',
                                    'Intensity plot'])

# Surface plot from z data.
lighting_effects = dict(ambient=0.2, roughness=0.5,
                        diffuse=0.8, fresnel=0.2, specular=0.05)
fig.add_trace(go.Surface(z=z, x=x, y=y, colorscale='gray_r', lighting=lighting_effects), row=1, col=1)

fig.update_scenes(xaxis=dict(ticks='outside', ticklen=10, title='x (range)'),
                  yaxis=dict(ticks='outside', ticklen=10, title='y (crossrange'),
                  zaxis=dict(ticks='outside', ticklen=10 ,title='Magnitude'),
                  camera_projection_type = "orthographic",
                  row=1, col=1)

fig.update_scenes(xaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2),
    yaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2),
    zaxis=dict(
        backgroundcolor="rgb(245, 245, 245)",
        gridcolor="black",
        showbackground=True,
        zerolinecolor="red",
        zerolinewidth=3,
        gridwidth=2,
        tickwidth=2), row=1, col=1)


# Gray-scale heatmap from z data.
#Axis_Labels = dict(x = "Range", y = "Crossrange")
fig.add_trace(go.Heatmap(z=z, colorscale='gray_r'), row=1, col=2)

fig.update_xaxes(title='Range', ticks="outside", ticklen=10, row=1, col=2)
fig.update_yaxes(title='Crossrange', ticks="outside", ticklen=10, row=1, col=2)
fig.update_xaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True), row=1, col=2)
fig.update_yaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True), row=1, col=2)
fig.update_xaxes(showline=True, linewidth=2, linecolor='black', mirror=True, row=1, col=2)
fig.update_yaxes(showline=True, linewidth=2, linecolor='black', mirror=True, row=1, col=2)

fig.update_layout(height=700, width=1200, title_text="Side By Side Subplots")
fig.show()

Thanks for that quick reply, r-beginners (he said, 5d later). That indeed solves the problem.

But I wonder why one has to use a separate API for plots when they happen to be placed into a subplot. Surely Iโ€™m not the only person to think this is klunky and 20x harder. Why canโ€™t one design the plots as standalone entities and then just plug them into something like

make_suplots([[fig1, fig2],[fig3, fig4]])?

Do you think I should make a feature request?

1 Like

Simply put, express includes functionality for subplots from the start. For example, subplotting on a categorical variable is accomplished by simply specifying the column names. To create arbitrarily different graphs, a subplotting function is provided, which is structured to create graphs with graph objects on the subplots. This is about all I can answer as far as I understand. For more information, see Plotly express Overview in the reference.

Thank you, r-beginners. Iโ€™ll check into that. But for now, my interest is mostly in surface plots and Express does not deal with surface plots at all.

I just did a quick check (again) of the Express link. The only subplot I saw used Dash or data frames and donโ€™t use either of those. โ€œsubplotโ€ appears only once on the page and it is not germain AFAIKT.