ax.get_xlim() doesnt work with datetimeindex

Question:

ax.get_xlim doesnt provide the right result. When running the code below, I get xmin as 1970-01-01 instead of 2003-01-01.

Does anyone know how to fix it?

data = pd.DataFrame({
    'Date': pd.date_range('1980-01-01', '2023-01-01', freq='M'),
    'Value': np.random.rand(516)
})
data=data.set_index('Date')
data.index=pd.to_datetime(data.index)
data=data.resample('M').last()

data=data['2003-01-01':]
fig, ax = plt.subplots()
xmin, xmax = ax.get_xlim()
ax.plot(data)
print(pd.Timestamp(xmin)) 
Asked By: user20856754

||

Answers:

First, you should pull the xlims after the plot rather than before. Otherwise, it’s just the default starting [0, 1].

Then you need to use matplotlib.dates.num2date()

from matplotlib import dates

data = pd.DataFrame({
    'Date': pd.date_range('1980-01-01', '2023-01-01', freq='M'),
    'Value': np.random.rand(516)
})
data=data.set_index('Date')
data.index=pd.to_datetime(data.index)
data=data.resample('M').last()

data=data['2003-01-01':]
fig, ax = plt.subplots()

ax.plot(data)
xmin, xmax = ax.get_xlim()

print(dates.num2date(xmin)) 
Answered By: Michael Cao

You have 2 minor issues here:

  1. The limits are not appropriately available until you actually plot the data, so you’ll need to call ax.get_xlim AFTER ax.plot
  2. Matplotlib converts datetimes into floats that represent the number of days after 1970-01-01, whereas pandas represents dates by the number of nanoseconds after 1970-01-01.
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

data = pd.DataFrame({
    'Date': pd.date_range('1980-01-01', '2023-01-01', freq='M'),
    'Value': np.random.rand(516)
})
data=data.set_index('Date')
data.index=pd.to_datetime(data.index)
data=data.resample('M').last()

data=data['2003-01-01':]
fig, ax = plt.subplots()
ax.plot(data)

xmin, xmax = ax.get_xlim()

# Using pandas mechanics to convert values
print(pd.Timestamp(xmin, unit='D')) # 2002-02-01 07:12:00

# Using matplotlib mechanics
from matplotlib.dates import num2date
print(num2date(xmin)) # 2002-02-01 07:12:00+00:00

To convert the values using pd.Timestamp or pd.to_datetime you’ll need to specify the unit='D' to represent that each unit of the value is 1 day since the epoch (1970-01-01).

Alternatively, you can also use matplotlib built in date conversion function: matplotlib.dates.num2date to get a numpy datetime back.

Answered By: Cameron Riddell

I’d like to add on to Michel Cao’s response to provide a bit more insight as to what’s happening.

From the matplotlib documentation on date format:

Matplotlib represents dates using floating point numbers specifying the number of days since a default epoch of 1970-01-01 UTC; for example, 1970-01-01, 06:00 is the floating point number 0.25.

So if after correcting the order of our line execution as mentioned in the Cao’s response. Running

xmin, xmax = ax.get_xlim()

Will result in xmin == 11719.3. This is the correct expected date, but just in the matplotlib floating point format. Calling num2date will convert our floating point number to the expected date of 2002-02-01 07:12:00+00:00.

Answered By: nlivingstone
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.