Plotly - multiple (three) labels on x axis

71 views Asked by At

I have a dataset with columns for week, month and year, and I would like to plot variable in time using week, month and year as labels. Can something like this be done with plotly in python?

This is how I want the labels

I am able to get 2 labels (week, month) using following code: df is my dataframe with columns week, month, year, value.

fig = go.Figure()
fig.add_trace(go.Scatter(x=[df['month'], df['week']],
                             y=list(df['value'])))
return fig
2

There are 2 answers

0
r-beginners On

As far as I know, it is possible to have up to two levels of hierarchy on the x-axis. As a workaround, you can combine the year and month to get something close to what you intend. I created the code based on the scatter y-ru in the reference.

import plotly.express as px
import plotly.graph_objects as go
import datetime
import pandas as pd

df = px.data.stocks()[:30]
df['date'] = pd.to_datetime(df['date'])

df['week'] = df['date'].dt.isocalendar().week
df['month'] = df['date'].dt.month
df['year'] = df['date'].dt.year

fig = go.Figure()
fig.add_trace(go.Scatter(x=[[f'{m:02}<br>{y}' for y,m in zip(df['year'].tolist(),df['month'].tolist())], df['week']], y=list(df['GOOG'])))

fig.show()

enter image description here

0
Ratislaus On

You could add a secondary X-axis, placing weekly ticks with their labels on it, inside the plot. If you need some special ticks for years, you could place them as minor ticks on that secondary X-axis too, but outside of the plot:

import plotly.graph_objects as go
from plotly.graph_objs.layout import YAxis, XAxis
import plotly.express as px

df = px.data.stocks()

# grab some data
df = df.head(60)

# apply the layout with a secondary X-axis
layout = go.Layout(
    title="Plot with ticks for weeks, months, and years on the X-axis",
    # main X-axis with monthly ticks, where each label contains a month and a year 
    xaxis = XAxis(
        ticks="outside",
        ticklabelmode="period", 
        tickcolor="black", 
        ticklen=10,
        dtick="M1",
        tickformat="%m\n%Y"
    ),
    # secondary X-axis having weekly ticks with inside labels, and having huge outside "minor" ticks corresponding to years
    xaxis2 = XAxis(
        overlaying="x",
        ticks="inside",
        ticklabelposition="inside",
        ticklabelmode="period",
        tickcolor="black", 
        ticklen=10,
        dtick=7*24*60*60*1000,
        tickformat="%V",
        griddash="dot",
        gridcolor="white",
        minor=dict(
            ticks="outside",
            ticklen=40,
            dtick="M12"
        )
    ),
    yaxis=dict(
        title="Y values"
    ),
)

# plot data
fig = px.line(df, x="date", y=df.columns,
              title="custom tick labels")

# apply the layout with a secondary X-axis
fig.update_layout(layout)

# place an invisible trace on the secondary X axis, to avoid automatic hiding of the axis
fig.add_trace(
    go.Scatter(x=df["date"], y=df["GOOG"], name="some data", xaxis="x2", opacity=0, showlegend=False),
)

fig.show()

In this method you need to place a transparent trace on the secondary X-axis, otherwise Plotly will automatically hide the axis. The result:

enter image description here

If you rescale the HTML page with that image, you may end up with vertically reoriented labels for weeks:

enter image description here

If you squeeze the page too much, the labels may even get lumped:

enter image description here

To avoid that, you may need to adjust the dtick parameter, which holds the step in-between ticks in milliseconds in this case. For example, if you remove dtick=7*24*60*60*1000, from the secondary X-axis layout definition, only some of the weekly labels will be shown on the secondary X-axis:

enter image description here

But if you zoom the plot enough, you will see all the labels again:

enter image description here