Search code examples
pythonplotlyhistogrambordersubplot

Plotly add border to a specific subplot


So I need to draw a graph with two subplots, and want to add borders to the one above. I am using plotly, but failed to find a way to do so. The borders here are essentially the solid line along the axes, but as a rectangle. Does anyone know how to add borders (axes) to a specific subplot?

My code:

#random generate points#

x1=np.random.normal(50, 10, 1000) 
x2=np.random.normal(30, 10, 1000)
x3=np.random.normal(70, 10, 1000)



x1_kde=gaussian_kde(x1)
x1_range=linspace(min(x1), max(x1),len(x1))
x1_evaluated=x1_kde.evaluate(x1_range)

x2_kde=gaussian_kde(x2)
x2_range=linspace(min(x2), max(x2),len(x2))
x2_evaluated=x2_kde.evaluate(x2_range)

x3_kde=gaussian_kde(x3)
x3_range=linspace(min(x3), max(x3),len(x3))
x3_evaluated=x3_kde.evaluate(x3_range)

def bedslistmaker(x,n):
    listofbeds = [x] * n
    return listofbeds

x1_beds=bedslistmaker('bed 1',len(x1))
x2_beds=bedslistmaker('bed 2',len(x2))
x3_beds=bedslistmaker('bed 3',len(x3))

First three traces for the histogram (KDE)

trace1 = go.Scatter(x=x1_range,y=x1_evaluated,xaxis="x2", yaxis="y2", \
                    mode='lines',line={'color': '#377e22','width': 1},marker={'color':'#377e22'},\
                    fill='tozeroy',fillcolor='rgba(55, 126, 34,  0.25)',showlegend=True,name='x1')


trace2 = go.Scatter(x=x2_range,y=x2_evaluated,xaxis="x2", yaxis="y2", \
                    mode='lines',line={'color': '#0480A6','width': 1},marker={'color':'#0480A6'},\
                    fill='tozeroy',fillcolor='rgba(4, 128, 166,  0.25)',showlegend=True,name='x2')
                    
    
trace3 = go.Scatter(x=x3_range,y=x3_evaluated,xaxis="x2", yaxis="y2", \
                    mode='lines',line={'color': '#FF0000','width': 1},marker={'color':'#FF0000'},\
                    fill='tozeroy',fillcolor='rgba(255, 0, 0,  0.25)',showlegend=True,name='x3')

Last three for the sticks below

trace4=go.Scatter(x=x1,y=x1_beds,mode="markers",xaxis= "x1", yaxis= "y1",marker={
    "color": "#377e22", 
    "symbol": "line-ns-open"},
    text=None,
    showlegend=False)

trace5=go.Scatter(x=x2,y=x2_beds,mode="markers",xaxis= "x1", yaxis= "y1",marker={
    "color": "#0480A6", 
    "symbol": "line-ns-open"
  }, text=None,showlegend=False)

trace6=go.Scatter(x=x3,y=x3_beds,mode="markers",xaxis= "x1", yaxis= "y1",marker={
    "color": "#FF0000", 
    "symbol": "line-ns-open"
  }, text=None,showlegend=False)


data=[trace1,trace2,trace3,trace4,trace5,trace6]

layouts

layout = go.Layout(
    
    xaxis1=go.layout.XAxis(
        domain=[0.00, 1],
        anchor="x1",
        showticklabels=False),


    yaxis1=go.layout.YAxis(
        domain=[0.01, 0.17],
        anchor="y1",
        showticklabels=False,
        title=go.layout.yaxis.Title(
            font=dict(
                family='Courier New, monospace',
                size=15,
                color='#7f7f7f'))),
    yaxis2=go.layout.YAxis(
        domain=[0.17, 1],
        anchor="y2",
        showticklabels=True,
        title=go.layout.yaxis.Title(

            text='Probability Density',
            font=dict(
                family='Courier New, monospace',
                size=15,
                color='#7f7f7f'))),
)


fig=go.Figure(data=data,layout=layout)



#fig.layout.update(showlegend=False)
fig.layout.update(template='plotly_white')#barmode='overlay'

fig.update_layout(
    legend=go.layout.Legend(
        x=0.73,
        y=0.97,
        traceorder="normal",
        font=dict(
            family="Courier New,monospace",
            size=10,
            color="#7f7f7f"
        ),
        #bgcolor="white",
        bordercolor="black",
        borderwidth=1
        
        
        
        
    )   
)

                 



fig.update_layout(
    margin=dict(l=80, r=80, t=50, b=80))
    
fig.layout.update(template='plotly_white')#barmode='overlay'

fig.update_layout(autosize=False,width=1000,height=618)
    
fig.show()

Original figure

Figure I would like to have (the border was drawn by hand)


Solution

  • You can set axis lines with so called mirrors for any subplot by referencing their position with row, col like this:

    fig.update_xaxes(showline = True, linecolor = 'black', linewidth = 1, row = 1, col = 1, mirror = True)
    fig.update_yaxes(showline = True, linecolor = 'black', linewidth = 1, row = 1, col = 1, mirror = True)
    

    Plot:

    enter image description here

    Code:

    from plotly.subplots import make_subplots
    import plotly.graph_objects as go
    
    fig = make_subplots(rows=2, cols=1)
    
    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.update_xaxes(showline = True, linecolor = 'black', linewidth = 1, row = 1, col = 1, mirror = True)
    fig.update_yaxes(showline = True, linecolor = 'black', linewidth = 1, row = 1, col = 1, mirror = True)
    
    fig.update_layout(height=600, width=600, title_text="Border for upper subplot")
    f = fig.full_figure_for_development(warn=False)
    fig.show()