Remove/don't display one of the secondary X axis values in plotly

Question:

Context: I’m trying to plot a barplot with line plot using plotly with secondary axis. On the secondary X axis, I’m trying to make it so that we can see categorical values on top of the chart ("pre","during" and "post").

The approach I’m trying can be seen on the code below

Minimal reproducible code:

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
import base64
import plotly.graph_objects as go
from plotly.subplots import make_subplots

plot_df = pd.DataFrame({'time':['2022-01-01','2022-01-02','2022-01-03','2022-01-04','2022-01-05'],'A':[2.1,2.4,3.2,4.2,2.4],'B':[12,23,24,27,17],'C':[np.nan,500,200,np.nan,np.nan],'D':['pre','during','during','post','post']})
plot_df


fig = make_subplots(specs=[[{"secondary_y": True}]])

fig.add_trace(
    go.Bar(
        x=[
            plot_df['D'],
            plot_df['time']
        ],
        y=plot_df['C'],
        showlegend=True,
        name='C'
    )
)

fig.add_trace(
    go.Bar(
        x=plot_df['time'],
        y=plot_df['C'],
        name='C',
        visible=False
    )
)

fig.add_trace(
    go.Scatter(
        mode='lines',
        x=plot_df['time'], 
        y=plot_df['A'],
        name='A'),
        secondary_y=True
)

fig.add_trace(
    go.Scatter(
        mode='lines',
        x=plot_df['time'], 
        y=plot_df['B'],
        name='B'),
        secondary_y=True
)

fig.update_layout(
    #margin=dict(l=2, r=1, t=55, b=2),
    autosize=True,
    xaxis=dict(title_text="Time"),
    yaxis=dict(title_text="C"),
    width=1000,
    xaxis2= {'anchor': 'y', 'overlaying': 'x', 'side': 'top'}
    )

fig.data[0].update(xaxis='x2')

fig.show()

Current output:

The current output I’m getting to is this:

enter image description here

Which is close to what I want, however, how can I remove the dates that are present right below the pre, during and post strings on the secondary X axis? Also, how can I make it so that the barplot is behind the lines?

Thanks!

Asked By: Chronicles

||

Answers:

Interesting issue. Since the first subplot has a multicategorical axis, both sets of data have to remain in place. I tried replacing the dates with empty strings which removes the dates, leaving the pre, during, and post strings, but condenses the bars since they both now have x-axis [‘during’, ”].

Poor First attempt:

Figure 1

It also doesn’t look like plotly allows multiple colors in an axis, just in case we wanted to try coloring the dates white.

The only other solution I can think of is making a slightly simpler plot and adding annotations at the top to show your time periods. I also added dashed lines to make it easier to differentiate between time periods.

fig = make_subplots(specs=[[{"secondary_y": True}]])


fig.add_trace(
    go.Bar(
    x=plot_df['time'],
    y=plot_df['C'],
    name='C',
    showlegend=True,
    )
)

fig.add_trace(
    go.Scatter(
    mode='lines',
    x=plot_df['time'],
    y=plot_df['A'],
    name='A'),
    secondary_y=True
)

fig.add_trace(
    go.Scatter(
    mode='lines',
    x=plot_df['time'],
    y=plot_df['B'],
    name='B'),
    secondary_y=True
)

fig.update_layout(
    #margin=dict(l=2, r=1, t=55, b=2),
    autosize=True,
    width=1000,
    )
fig.update_xaxes(title='time')
fig.update_yaxes(title='C', secondary_y=False)
fig.update_yaxes(title='A & B', secondary_y=True)

for d in plot_df['D'].unique():
    fig.add_annotation(text=d, x=plot_df['time'][plot_df['D']==d].median(), yref='paper', y=1.05, showarrow=False)

fig.add_vline(x=pd.to_datetime('2022-01-01-12'), line_width=1, line_dash='dash', line_color='gray')
fig.add_vline(x=pd.to_datetime('2022-01-03-12'), line_width=1, line_dash='dash', line_color='gray')

fig.show()

Final Figure

Hope this helps!

Answered By: amance
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.