0

I would like to show datetimes as ticklabels on the x-axis of a plot via ax.imshow(). I first tried putting the limits (as datetime objects) into extent, but it appears that extent only accepts arguments of type <float/int>. So instead, I would like to create the original plot via ax.imshow(...), then make the x-axis invisible, then add in the correct xticks and xlim.

I found a similar problem solved using a different approach in this example, but I think my use-case is slightly different; I don't need to convert any time-stamps, but I do know the xlim of the data (in terms of datetime objects). Also, I do not think the suggested use of matplotlib.dates.date2num fits my use-case since some of the data is spaced less than one day apart, but date2num uses days as a base-unit.

I am stuck trying to make this work using my alternate approach; a simple mini-example is below.

import numpy as np
import datetime
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

def f(x, y):
    return np.sqrt(np.square(x) + np.square(y))

## SAMPLE DATA
x = np.arange(10) ## elapsed minutes
y = np.square(x) ## arbitrary y-values
X, Y = np.meshgrid(x, y)
Z = f(X, Y)

## DATETIMES FOR ALTERNATE AXIS
lower_dt = datetime.datetime(1999, 1, 1, 0, 0, 0)
# upper_dt = datetime.datetime(2001, 10, 31, 0, 0, 0)
upper_dt = datetime.datetime(1999, 1, 1, x.size-1, 0, 0)

## DO PLOT
fig, ax = plt.subplots()
ax.xaxis.set_visible(False)
# ax.xaxis.tick_top()
ax.imshow(
    Z,
    origin='lower',
    cmap='Oranges',
    norm=Normalize(vmin=np.nanmin(Z), vmax=np.nanmax(X)),
    extent=(x[0], x[-1], y[0], y[-1]))

## CONVERT XTICKLABELS OF X-AXIS TO DATETIME
mirror_ax = ax.twiny()
# mirror_ax = ax.figure.add_subplot(ax.get_subplotspec(), frameon=False)
mirror_ax.set_xlim([lower_dt, upper_dt])

plt.show()
plt.close(fig)

The obtained plot can be seen here: enter image description here

I notice that the xticks are shown at the top instead of the bottom of the plot - this is unwanted behavior; using ax.tick_top (commented out above) does not change this. Even worse, the x-axis limits are not retained. I realize I could manually change the xticklabels via ax.get_xticks() and ax.set_xticklabels(...), but I would prefer to leave that for date-formatters and date-locators via matplotlib.

How can I use the approach outlined above to create a "mirror/alternate" x-axis of datetime units such that this x-axis is the same size/orientation of the "original/invisible" x-axis of float/integer units?

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • I’d suggest you use pcolormesh instead of imshow. – Jody Klymak Jan 15 '21 at 16:01
  • It seems you do not want to create a twin axis but use `ax.xaxis.tick_top()` instead to move the x-labels to the desired position. Why did you comment it out and use your approach instead? – Mr. T Jan 15 '21 at 19:27

0 Answers0