Plot a categorical variable below/above the X axis (as a secondary X axis) on a plot

Context: I have a dataframe and I’m plotting a line plot and a bar plot on the same chart. Now, I’d like to add a type of “timeline” below the date on the main X axis or above the chart as a secondary x axis.

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.Line(x=plot_df['time'], y=plot_df['A'],name='A'),secondary_y=True)
    fig.add_trace(go.Line(x=plot_df['time'], y=plot_df['B'],name='B'),secondary_y=True)
    
    fig.add_trace(go.Bar(x=plot_df['time'], y=plot_df['C'],name='C'), secondary_y=False)
    
    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
        )
    
    fig.show()

From this, I get this plot:
Image: (uploaded using ImgBB) newplot-2 — ImgBB

The idea would essentially to take the column D and plot the “pre”,“during” and “post” on top of the plot or right below the “time” on the x axis (whichever would be easier/more visually appealing)

How could I do that?

The end goal would be something like this (doesn’t have to have the same colors, or box size, or text font, etc, I’d just like to know how we could get something like this going on the chart)

Thanks!

Welcome to the forums @roo.

Does this help or do you need to have the ‘Pre, During, Post’ with a different background/font/color?

Applied to your example (I changed from the deprecated Go.Line to go.Scatter)

import pandas as pd
import numpy as np
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']})

x = [plot_df.D, plot_df.time]

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

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

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

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
    )

fig.show()

Result: