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))
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))
You have 2 minor issues here:
- The limits are not appropriately available until you actually plot the data, so you’ll need to call
ax.get_xlim
AFTER ax.plot
- 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.
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
.
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))
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))
You have 2 minor issues here:
- The limits are not appropriately available until you actually plot the data, so you’ll need to call
ax.get_xlim
AFTERax.plot
- 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.
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
.