matplotlib/pandas 中日期的内部表示不一致
Inconsistent internal representation of dates in matplotlib/pandas
import pandas as pd
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-02'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot()
print(ax.get_xlim())
# Out: (736066.7, 736469.3)
现在,如果我们更改最后日期。
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-01'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot()
print(ax.get_xlim())
# Out: (184.8, 189.2)
第一个例子似乎与matplotlib docs一致:
Matplotlib represents dates using floating point numbers specifying the number of days since 0001-01-01 UTC, plus 1
为什么第二个例子 return 看起来完全不同?我正在使用 pandas 版本 0.22.0 和 matplotlib 版本 2.2.2.
在第二个示例中,如果您查看图表,matplotlib 不会给出日期,而是给出季度值:
本例中的日期正好是六个月,因此相隔两个季度,这大概就是您看到此行为的原因。虽然我无法在文档中找到它,但 xlim 在这种情况下给出的数字与自 Unix 纪元(1970 年 1 月 1 日)以来的季度数一致。
Pandas使用不同的单位来表示坐标轴上的日期和时间,这取决于dates/times使用的范围。这意味着正在使用不同的定位器。
第一种情况,
print(ax.xaxis.get_major_locator())
# Out: pandas.plotting._converter.PandasAutoDateLocator
第二种情况
print(ax.xaxis.get_major_locator())
# pandas.plotting._converter.TimeSeries_DateLocator
您可以使用 x_compat
参数强制 pandas 始终使用 PandasAutoDateLocator
,
df.plot(x_compat=True)
这将确保始终获得相同的日期时间定义,与 matplotlib.dates
约定一致。
缺点是这会删除不错的季度更新
并将其替换为标准滴答
另一方面,它将允许使用非常可定制的 matplotlib.dates
代码和格式化程序。例如获取季度 ticks/labels
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as mticker
import pandas as pd
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-01'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot(x_compat=True)
# Quarterly ticks
ax.xaxis.set_major_locator(mdates.MonthLocator((1,4,7,10)))
# Formatting:
def func(x,pos):
q = (mdates.num2date(x).month-1)//3+1
tx = "Q{}".format(q)
if q == 1:
tx += "\n{}".format(mdates.num2date(x).year)
return tx
ax.xaxis.set_major_formatter(mticker.FuncFormatter(func))
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
plt.show()
import pandas as pd
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-02'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot()
print(ax.get_xlim())
# Out: (736066.7, 736469.3)
现在,如果我们更改最后日期。
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-01'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot()
print(ax.get_xlim())
# Out: (184.8, 189.2)
第一个例子似乎与matplotlib docs一致:
Matplotlib represents dates using floating point numbers specifying the number of days since 0001-01-01 UTC, plus 1
为什么第二个例子 return 看起来完全不同?我正在使用 pandas 版本 0.22.0 和 matplotlib 版本 2.2.2.
在第二个示例中,如果您查看图表,matplotlib 不会给出日期,而是给出季度值:
本例中的日期正好是六个月,因此相隔两个季度,这大概就是您看到此行为的原因。虽然我无法在文档中找到它,但 xlim 在这种情况下给出的数字与自 Unix 纪元(1970 年 1 月 1 日)以来的季度数一致。
Pandas使用不同的单位来表示坐标轴上的日期和时间,这取决于dates/times使用的范围。这意味着正在使用不同的定位器。
第一种情况,
print(ax.xaxis.get_major_locator())
# Out: pandas.plotting._converter.PandasAutoDateLocator
第二种情况
print(ax.xaxis.get_major_locator())
# pandas.plotting._converter.TimeSeries_DateLocator
您可以使用 x_compat
参数强制 pandas 始终使用 PandasAutoDateLocator
,
df.plot(x_compat=True)
这将确保始终获得相同的日期时间定义,与 matplotlib.dates
约定一致。
缺点是这会删除不错的季度更新
并将其替换为标准滴答
另一方面,它将允许使用非常可定制的 matplotlib.dates
代码和格式化程序。例如获取季度 ticks/labels
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as mticker
import pandas as pd
index = pd.to_datetime(['2016-05-01', '2016-11-01', '2017-05-01'])
data = pd.DataFrame({'a': [1, 2, 3],
'b': [4, 5, 6]}, index=index)
ax = data.plot(x_compat=True)
# Quarterly ticks
ax.xaxis.set_major_locator(mdates.MonthLocator((1,4,7,10)))
# Formatting:
def func(x,pos):
q = (mdates.num2date(x).month-1)//3+1
tx = "Q{}".format(q)
if q == 1:
tx += "\n{}".format(mdates.num2date(x).year)
return tx
ax.xaxis.set_major_formatter(mticker.FuncFormatter(func))
plt.setp(ax.get_xticklabels(), rotation=0, ha="center")
plt.show()