Matplotlib的日期格式化程序无法为轴标签工作

36
我试图调整x轴的日期刻度标签格式,使其仅显示年份和月份值。根据我在网上找到的信息,我需要使用mdates.DateFormatter,但是它在我的当前代码中没有任何效果。有人看到问题出在哪里吗?(日期是pandas数据框的索引)
import matplotlib.dates as mdates
import matplotlib.pyplot as plt
import pandas as pd 

fig = plt.figure(figsize = (10,6))
ax = fig.add_subplot(111)

ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

basicDF['some_column'].plot(ax=ax, kind='bar', rot=75)

ax.xaxis_date()

enter image description here

重现场景代码:

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

rng = pd.date_range('1/1/2014', periods=20, freq='m')

blah = pd.DataFrame(data = np.random.randn(len(rng)), index=rng)

fig = plt.figure(figsize = (10,6))
ax = fig.add_subplot(111)

ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))

blah.plot(ax=ax, kind='bar')

ax.xaxis_date()

仍然无法只显示年份和月份。

如果我在.plot之后设置格式,会出现以下错误:

  

ValueError:DateFormatter发现了一个x=0的值,这是一个非法日期。这通常是因为您尚未告知轴正在绘制日期,例如,使用x.xaxis_date()

如果我在ax.xaxis_date()之前或之后放置它,情况也是一样的。


我在这里找到了另一个好答案:https://dev59.com/Fl0a5IYBdhLWcg3wmZzC - Mahdi
4个回答

40

pandas对自定义日期时间格式的支持不太好。

在这种情况下,您需要使用原始的matplotlib。

import numpy
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas

N = 20
numpy.random.seed(N)

dates = pandas.date_range('1/1/2014', periods=N, freq='m')
df = pandas.DataFrame(
    data=numpy.random.randn(N), 
    index=dates,
    columns=['A']
)

fig, ax = plt.subplots(figsize=(10, 6))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
ax.bar(df.index, df['A'], width=25, align='center')

这给了我:

在此输入图片描述


2
2020年是否仍然如此? - Simon Kohlmeyer
1
@SimonKohlmeyer 我的例子是自包含的。我建议你尝试并修改它以查看结果。 - Paul H
对于所有人来说,要测试这个,你必须添加 fig.show(),而且它仍然适用于 Python 3.8.5 和 Pandas 1.1.3。 - Simon Kohlmeyer

10

只使用pandas的解决方案

您可以使用DatetimeIndex并利用时间戳的日期时间属性创建漂亮格式的刻度。除非您想在使用matplotlib的交互界面缩放时获得动态刻度(对于比本示例更长的时间范围更为相关),否则来自matplotlib.dates的刻度定位器和格式化程序在这种情况下并不必要。

import numpy as np   # v 1.19.2
import pandas as pd  # v 1.1.3

# Create sample time series with month start frequency, plot it with a pandas bar chart
rng = np.random.default_rng(seed=1) # random number generator
dti = pd.date_range('1/1/2014', periods=20, freq='m')
df = pd.DataFrame(data=rng.normal(size=dti.size), index=dti)
ax = df.plot.bar(figsize=(10,4), legend=None)

# Set major ticks and tick labels
ax.set_xticks(range(df.index.size))
ax.set_xticklabels([ts.strftime('%b\n%Y') if ts.year != df.index[idx-1].year
                    else ts.strftime('%b') for idx, ts in enumerate(df.index)])
ax.figure.autofmt_xdate(rotation=0, ha='center');

pd_bar_chart_date_ticks


1

我遇到了同样的问题,我使用了一个解决方法将日期时间格式的索引转换为所需的字符串格式:

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

rng = pd.date_range('1/1/2014', periods=20, freq='m')

blah = pd.DataFrame(data = np.random.randn(len(rng)), index=rng)

fig = plt.figure(figsize = (10,6))
ax = fig.add_subplot(111)

# transform index to strings
blah_test = blah.copy()
str_index = []
for s_year,s_month in zip(blah.index.year.values,blah.index.month.values):
    # build string accorind to format "%Y-%m"
    string_day = '{}-{:02d}'.format(s_year,s_month)
    str_index.append(string_day)
blah_test.index = str_index

blah_test.plot(ax=ax, kind='bar', rot=45)
plt.show()

这段文字的意思是:“这导致了下面的图形:figure with labels formatted correctly”,其中保留了HTML标记和图片链接。

1

被接受的答案声称"pandas与自定义日期时间格式不兼容",但是您可以利用pandas的to_datetime()函数在数据框中使用现有的日期时间序列:

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

rng = pd.date_range('1/1/2014', periods=20, freq='m')

blah = pd.DataFrame(data = np.random.randn(len(rng)), index=pd.to_datetime(rng))

fig, ax = plt.subplots()

ax.xaxis.set_major_formatter(DateFormatter('%m-%Y'))
ax.bar(blah.index, blah[0], width=25, align='center')

将会产生以下结果:

a bar graph with the dates formatted as described

您可以在此处查看不同的可用格式。

8
由于两个原因导致得分为-1——pd.date_rangepd.to_datetime都返回DatetimeIndex,所以pd.to_datetime(rng)rng没有任何区别。除此之外,这个答案与被接受的答案没有什么区别——你使用了相同的ax.bar方法而不是df.plot(kind='bar') - kevinsa5

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接