Search code examples
pythonplotlyvisualizationplotly-express

How to set independent parameters for subplots in Plotly?


I’m working with Plotly in Python to create a figure with two subplots, each containing a density contour plot. I want to set different bin sizes (nbinsx and nbinsy) for each subplot. However, it seems that setting these parameters for one subplot affects the other, and I’m unable to have independent bin sizes for each.

Here’s a minimal working example:

import plotly.graph_objs as go
from plotly.subplots import make_subplots
import plotly.express as px
import pandas as pd

# Create some dummy data
df_plot = pd.DataFrame({
    'g_w1': [i for i in range(30)],
    'w1_w2': [i*0.5 for i in range(30)],
    'bp_g': [i*2 for i in range(30)],
    'g_rp': [i*0.3 for i in range(30)],
    'type': ['typeA']*15 + ['typeB']*15
})

# Create a subplot with 1 row and 2 columns
fig = make_subplots(rows=1, cols=2)

# First density contour plot for 'crossmatches'
fig_crossmatches = px.density_contour(df_plot, x="g_w1", y="w1_w2", color='type', nbinsx=28, nbinsy=28)
# Add the 'crossmatches' plot to the first subplot
for trace in fig_crossmatches.data:
    fig.add_trace(trace, row=1, col=1)

# Second density contour plot for 'no crossmatches'
fig_nonmatches = px.density_contour(df_plot, x="bp_g", y="g_rp", color='type')
# Add the 'no crossmatches' plot to the second subplot
for trace in fig_nonmatches.data:
    fig.add_trace(trace, row=1, col=2)

# Attempt to update the bin sizes for the second subplot
fig.update_traces(selector=dict(row=1, col=2), nbinsx=128, nbinsy=128)

# Update the layout if needed
fig.update_layout(autosize=False, width=1500, height=600)

# Show the figure
fig.show()

When I run this code, the nbinsx and nbinsy for the second subplot do not seem to take effect. I’ve tried using update_traces but to no avail. How can I set independent bin sizes for each subplot in Plotly?


Solution

  • Because the figures are created separately, they share the same xbingroup and ybingroup (respectively 'x' and 'y' by default). You need to set distinct bingroups for one of the two figures, eg. let say the second one :

    # Second density contour plot for 'no crossmatches'
    fig_nonmatches = px.density_contour(df_plot, x="bp_g", y="g_rp", color='type', nbinsx=128, nbinsy=128)
    fig_nonmatches.update_traces(xbingroup='x2', ybingroup='y2')
    
    # Add the 'no crossmatches' plot to the second subplot
    for trace in fig_nonmatches.data:
        fig.add_trace(trace, row=1, col=2)
    

    Also, if you want to set the xaxis/yaxis titles from the two original figures to their respective subplot axes, you can do the following :

    fig.update_layout(
        xaxis_title=fig_crossmatches.layout['xaxis']['title'],
        yaxis_title=fig_crossmatches.layout['yaxis']['title'],
        xaxis2_title=fig_nonmatches.layout['xaxis']['title'],
        yaxis2_title=fig_nonmatches.layout['yaxis']['title']
    )