Last active
August 28, 2023 03:17
-
-
Save mjul/edace992c97528721242b91979f04844 to your computer and use it in GitHub Desktop.
Create secondary x-axis with date and days since start in Matplotlib
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Matplotlib secondary x-axis with dates and days since start | |
There is more than one way to do it, but only on right way to do it. | |
You can use `twiny()` to get another Axes and set its x-axis. | |
`secondary_xaxis` is your friend, but you need the right conversion functions. | |
#%% | |
import datetime | |
import numpy as np | |
import matplotlib.pyplot as plt | |
import matplotlib.dates as mdates | |
import matplotlib.ticker as ticker | |
start_dato = np.datetime64('2020-03-01', 'D') | |
days = np.arange(45) | |
dates = start_dato + days | |
#%% | |
# Testdata | |
a = 42 | |
b = 0.03 | |
ys = a*np.exp(b*days) | |
#%% md | |
## This is kind of a hack | |
#%% | |
# Use two axes (graphing areas) | |
fig, ax = plt.subplots() | |
fig.set_facecolor('0.9') | |
ax.plot(days, ys) | |
ax.set_yscale('log') | |
ax.grid(True) | |
ax2 = ax.twiny() | |
ax2.set_axisbelow(True) | |
xa2 = ax2.get_xaxis() | |
xa2.axis_date() | |
xa2.set_major_locator(mdates.MonthLocator()) | |
xa2.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) | |
xa2.set_minor_locator(mdates.DayLocator()) | |
#xa2.set_minor_formatter(mdates.DateFormatter('%d')) | |
ax2.plot(dates, ys) | |
plt.show() | |
#%% md | |
## This is another kind of hack | |
#%% | |
# Using two axes on top of each other, each with its own x-axis | |
fig, ax = plt.subplots() | |
fig.set_facecolor('green') | |
ax.set_yscale('log') | |
ax.grid(True) | |
ax.plot(dates, ys) | |
ax.xaxis_date() | |
x1 = ax.get_xaxis() | |
x1.set_major_locator(mdates.MonthLocator()) | |
x1.set_major_formatter(mdates.DateFormatter('%d-%b-%Y')) | |
x1.set_minor_locator(mdates.DayLocator()) | |
fig.autofmt_xdate() | |
x1.set_label('Dato') | |
ax2 = ax.twiny() | |
ax2.set_xlabel('Dage siden epidemistart') | |
x2 = ax2.get_xaxis() | |
x2.set_major_locator(ticker.MultipleLocator(10)) | |
ax2.plot(days, ys, alpha=0) # invisible plot, but it sets the axis to match the other one | |
plt.show() | |
#%% md | |
## This is the right approach | |
Use `secondary_xaxis`: | |
#%% | |
# Use secondary axis | |
# Konverteringsfunktioner, se | |
# https://matplotlib.org/3.1.0/gallery/subplots_axes_and_figures/secondary_axis.html | |
# | |
def dato_til_dag(x): | |
""" | |
x is in matplotlib datenums, so they are floats. | |
""" | |
y = x - mdates.date2num(start_dato) | |
return y | |
def dag_til_dato(x): | |
""" | |
return a matplotlib datenum (x is days since start of year) | |
""" | |
y = x + mdates.date2num(start_dato) | |
return y | |
fig, ax = plt.subplots() | |
fig.set_facecolor('xkcd:cream') | |
fig.autofmt_xdate() | |
ax.set_yscale('log') | |
ax.grid(True) | |
ax.plot(dates, ys) | |
ax.xaxis_date() | |
ax.set_xlabel('Dato') | |
dage_x = ax.secondary_xaxis('top', functions=(dato_til_dag, dag_til_dato)) | |
dage_x.set_xlabel('Dage siden epidemistart') | |
plt.show() | |
#%% | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment