Search code examples
pythonplotlyhistogram

How to set secondary x-axis and its range in plotly graph with subfigures?


does anyone know how to set a secondary x-axis and also its range in plotly?

I am trying to show a vertical histogram here but it is currently still too small

Vertical histogram

enter image description here

import pandas as pd
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from plotly.graph_objs.layout import YAxis,XAxis,Margin

x1 = np.linspace(0, 4, 41)
y1 = (x1-2)**3+2
y2 = x1*0+2

x1_sample = np.random.normal(2,0.3,5000)
y1_sample = (x1_sample-2)**3+2
data = np.column_stack((x1_sample, y1_sample))
df_hist = pd.DataFrame(data = data, columns = ['x1_sample', 'y1_sample'])


fig = make_subplots(rows=1, cols=2, specs = [[{"secondary_y": True}, {"secondary_y": True}]], horizontal_spacing=0.2)

# Subplot 1
## Line
fig.update_yaxes(range = [0, 4], dtick = 1, secondary_y=False)
fig.add_trace(
    go.Scatter(x = x1 , y = y1, mode='lines'),
    row = 1, col = 1
)

fig.add_trace(
    go.Scatter(x = x1, y = y2, mode = 'lines'),
    row = 1, col = 1
)

## Histogram
fig.update_yaxes(range = [0, 0.5], dtick = 0.1, secondary_y=True)
fig.add_trace(
    go.Histogram(x = df_hist['x1_sample'], histnorm='probability', nbinsx=40),
    secondary_y=True,
    row = 1, col = 1
)

fig.add_trace(
    go.Histogram(y = df_hist['y1_sample'], histnorm='probability', nbinsy=40),
    row = 1, col = 1
)


Solution

  • To get what you need in your example, just add the following lines to your setup:

    fig.update_layout(xaxis2= {'anchor': 'y', 'overlaying': 'x', 'side': 'top'})
    fig.data[3].update(xaxis='x2')
    fig.update_layout(xaxis2_range=[-0,0.6])
    

    Line 1 sets up a secondary x-axis, while line 2 assigns a trace to it. I'm assuming fig.data[3] is the correct trace but you can check that for yourself. Line 3, unsuprisingly, sets the range of the secondary x-axis.

    Plot

    enter image description here

    Complete code:

    import numpy as np
    import pandas as pd
    import plotly.graph_objects as go
    from plotly.subplots import make_subplots
    from plotly.graph_objs.layout import YAxis,XAxis,Margin
    
    
    x1 = np.linspace(0, 4, 41)
    y1 = (x1-2)**3+2
    y2 = x1*0+2
    
    x1_sample = np.random.normal(2,0.3,5000)
    y1_sample = (x1_sample-2)**3+2
    data = np.column_stack((x1_sample, y1_sample))
    df_hist = pd.DataFrame(data = data, columns = ['x1_sample', 'y1_sample'])
    
    
    fig = make_subplots(rows=1, cols=2, specs = [[{"secondary_y": True}, {"secondary_y": True}]],
                        horizontal_spacing=0.2,
                        shared_xaxes = False)
    
    # Subplot 1
    ## Line
    fig.update_yaxes(range = [0, 4], dtick = 1, secondary_y=False)
    fig.add_trace(
        go.Scatter(x = x1 , y = y1, mode='lines'),
        row = 1, col = 1
    )
    
    fig.add_trace(
        go.Scatter(x = x1, y = y2, mode = 'lines'),
        row = 1, col = 1
    )
    
    ## Histogram
    fig.update_yaxes(range = [0, 0.5], dtick = 0.1, secondary_y=True)
    fig.add_trace(
        go.Histogram(x = df_hist['x1_sample'], histnorm='probability', nbinsx=40),
        secondary_y=True,
        row = 1, col = 1
    )
    
    fig.add_trace(
        go.Histogram(y = df_hist['y1_sample'], histnorm='probability', nbinsy=40),
        row = 1, col = 1
    )
    
    fig.update_layout(xaxis2= {'anchor': 'y', 'overlaying': 'x', 'side': 'top'})
    fig.data[3].update(xaxis='x2')
    fig.update_layout(xaxis2_range=[-0,0.6])
    
    
    fig.show()