Python Pandas 时间序列图设置 x 轴主要和次要刻度和标签

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12945971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:14:52  来源:igfitidea点击:

Pandas timeseries plot setting x-axis major and minor ticks and labels

pythonmatplotlibpandas

提问by brenda

I want to be able to set the major and minor xticks and their labels for a time series graph plotted from a Pandas time series object.

我希望能够为从 Pandas 时间序列对象绘制的时间序列图设置主要和次要 xticks 及其标签。

The Pandas 0.9 "what's new" page says:

Pandas 0.9“新功能”页面说:

"you can either use to_pydatetime or register a converter for the Timestamp type"

“您可以使用 to_pydatetime 或为 Timestamp 类型注册转换器”

but I can't work out how to do that so that I can use the matplotlib ax.xaxis.set_major_locatorand ax.xaxis.set_major_formatter(and minor) commands.

但我无法弄清楚如何做到这一点,以便我可以使用 matplotlibax.xaxis.set_major_locatorax.xaxis.set_major_formatter(和次要)命令。

If I use them without converting the pandas times, the x-axis ticks and labels end up wrong.

如果我在不转换熊猫时间的情况下使用它们,则 x 轴刻度和标签最终会出错。

By using the 'xticks' parameter I can pass the major ticks to pandas.plot, and then set the major tick labels. I can't work out how to do the minor ticks using this approach. (I can set the labels on the default minor ticks set by pandas.plot)

通过使用 'xticks' 参数,我可以将主要刻度传递给 pandas.plot,然后设置主要刻度标签。我无法弄清楚如何使用这种方法进行小刻度。(我可以在 pandas.plot 设置的默认小刻度上设置标签)

Here is my test code:

这是我的测试代码:

import pandas
print 'pandas.__version__ is ', pandas.__version__
print 'matplotlib.__version__ is ', matplotlib.__version__    

dStart = datetime.datetime(2011,5,1) # 1 May
dEnd = datetime.datetime(2011,7,1) # 1 July    

dateIndex = pandas.date_range(start=dStart, end=dEnd, freq='D')
print "1 May to 1 July 2011", dateIndex      

testSeries = pandas.Series(data=np.random.randn(len(dateIndex)),
                           index=dateIndex)    

ax = plt.figure(figsize=(7,4), dpi=300).add_subplot(111)
testSeries.plot(ax=ax, style='v-', label='first line')    

# using MatPlotLib date time locators and formatters doesn't work with new
# pandas datetime index
ax.xaxis.set_minor_locator(matplotlib.dates.WeekdayLocator(byweekday=(1),
                                                           interval=1))
ax.xaxis.set_minor_formatter(matplotlib.dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.xaxis.grid(False, which="major")
ax.xaxis.set_major_formatter(matplotlib.dates.DateFormatter('\n\n\n%b%Y'))
plt.show()    

# set the major xticks and labels through pandas
ax2 = plt.figure(figsize=(7,4), dpi=300).add_subplot(111)
xticks = pandas.date_range(start=dStart, end=dEnd, freq='W-Tue')
print "xticks: ", xticks
testSeries.plot(ax=ax2, style='-v', label='second line',
                xticks=xticks.to_pydatetime())
ax2.set_xticklabels([x.strftime('%a\n%d\n%h\n%Y') for x in xticks]);
# set the text of the first few minor ticks created by pandas.plot
#    ax2.set_xticklabels(['a','b','c','d','e'], minor=True)
# remove the minor xtick labels set by pandas.plot 
ax2.set_xticklabels([], minor=True)
# turn the minor ticks created by pandas.plot off 
# plt.minorticks_off()
plt.show()
print testSeries['6/4/2011':'6/7/2011']

and its output:

及其输出:

pandas.__version__ is  0.9.1.dev-3de54ae
matplotlib.__version__ is  1.1.1
1 May to 1 July 2011 <class 'pandas.tseries.index.DatetimeIndex'>
[2011-05-01 00:00:00, ..., 2011-07-01 00:00:00]
Length: 62, Freq: D, Timezone: None

Graph with strange dates on xaxis

xaxis 上带有奇怪日期的图形

xticks:  <class 'pandas.tseries.index.DatetimeIndex'>
[2011-05-03 00:00:00, ..., 2011-06-28 00:00:00]
Length: 9, Freq: W-TUE, Timezone: None

Graph with correct dates

带有正确日期的图表

2011-06-04   -0.199393
2011-06-05   -0.043118
2011-06-06    0.477771
2011-06-07   -0.033207
Freq: D

Update:I've been able to get closer to the layout I wanted by using a loop to build the major xtick labels:

更新:通过使用循环来构建主要的 xtick 标签,我已经能够更接近我想要的布局:

# only show month for first label in month
month = dStart.month - 1
xticklabels = []
for x in xticks:
    if  month != x.month :
        xticklabels.append(x.strftime('%d\n%a\n%h'))
        month = x.month
    else:
        xticklabels.append(x.strftime('%d\n%a'))

However, this is a bit like doing the x-axis using ax.annotate: possible but not ideal.

但是,这有点像使用ax.annotate: 可能但不理想的 x 轴。

采纳答案by bmu

Both pandasand matplotlib.datesuse matplotlib.unitsfor locating the ticks.

两者pandasmatplotlib.datesmatplotlib.units定位蜱。

But while matplotlib.dateshas convenient ways to set the ticks manually, pandas seems to have the focus on auto formatting so far (you can have a look at the codefor date conversion and formatting in pandas).

但是,虽然matplotlib.dates有手动设置刻度的便捷方法,但到目前为止,pandas 似乎专注于自动格式化(您可以查看pandas 中日期转换和格式化的代码)。

So for the moment it seems more reasonable to use matplotlib.dates(as mentioned by @BrenBarn in his comment).

所以目前使用似乎更合理matplotlib.dates(正如@BrenBarn 在他的评论中提到的)。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt 
import matplotlib.dates as dates

idx = pd.date_range('2011-05-01', '2011-07-01')
s = pd.Series(np.random.randn(len(idx)), index=idx)

fig, ax = plt.subplots()
ax.plot_date(idx.to_pydatetime(), s, 'v-')
ax.xaxis.set_minor_locator(dates.WeekdayLocator(byweekday=(1),
                                                interval=1))
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d\n%a'))
ax.xaxis.grid(True, which="minor")
ax.yaxis.grid()
ax.xaxis.set_major_locator(dates.MonthLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('\n\n\n%b\n%Y'))
plt.tight_layout()
plt.show()

pandas_like_date_fomatting

pandas_like_date_fomatting

(my locale is German, so that Tuesday [Tue] becomes Dienstag [Di])

(我的语言环境是德语,所以星期二 [Tue] 变成 Dienstag [Di])