如何在离散轴上排序刻度标签(0 索引像条形图)

How to order the tick labels on a discrete axis (0 indexed like a bar plot)

我有一个包含此数据的数据框,想用 x 轴标签为月的条形图绘制它

import pandas as pd

data = {'Birthday': ['1900-01-31', '1900-02-28', '1900-03-31', '1900-04-30', '1900-05-31', '1900-06-30', '1900-07-31', '1900-08-31', '1900-09-30', '1900-10-31', '1900-11-30', '1900-12-31'],
        'Players': [32, 25, 27, 19, 27, 18, 18, 21, 23, 21, 26, 23]}
df = pd.DataFrame(data)

  Birthday Players
1900-01-31      32
1900-02-28      25
1900-03-31      27
1900-04-30      19
1900-05-31      27
1900-06-30      18
1900-07-31      18
1900-08-31      21
1900-09-30      23
1900-10-31      21
1900-11-30      26
1900-12-31      23

这就是我的

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

fig = plt.figure(figsize=(12, 7))
locator = mdates.MonthLocator()
fmt = mdates.DateFormatter('%b')
X = plt.gca().xaxis
X.set_major_locator(locator)
X.set_major_formatter(fmt)
plt.bar(month_df.index, month_df.Players, color = 'maroon', width=10)

但结果是这样的,标签从二月开始而不是一月

我不熟悉 matplotlib.dates,但因为您使用的是 pandas,所以有一些简单的方法可以使用 pandas.

来完成您需要的操作

这是我的代码:

import pandas as pd
import calendar
from matplotlib import pyplot as plt

# data
data = {'Birthday': ['1900-01-31', '1900-02-28', '1900-03-31', '1900-04-30', '1900-05-31', '1900-06-30', '1900-07-31', '1900-08-31', '1900-09-30', '1900-10-31', '1900-11-30', '1900-12-31'],
        'Players': [32, 25, 27, 19, 27, 18, 18, 21, 23, 21, 26, 23]}
df = pd.DataFrame(data)

# convert column to datetime
df["Birthday"] = pd.to_datetime(df["Birthday"], format="%Y-%m-%d")

# groupby month and plot bar plot
df.groupby(df["Birthday"].dt.month).sum().plot(kind="bar", color = "maroon")

# set plot properties
plt.xlabel("Birthday Month")
plt.ylabel("Count")
plt.xticks(ticks = range(0,12) ,labels = calendar.month_name[1:])

# show plot
plt.show()

输出:

通常,matplotlib.bar 由于各种原因不能很好地处理日期时间。手动设置 x 刻度位置和标签很容易,如下所示。这是一个 fixed formatter 方便的包装函数,但它可以让您轻松控制。

#generate data
data = pd.Series({
    '1900-01-31' : 32,    '1900-02-28' : 25,    '1900-03-31' : 27,
    '1900-04-30' : 19,    '1900-05-31' : 27,    '1900-06-30' : 18,
    '1900-07-31' : 18,    '1900-08-31' : 21,    '1900-09-30' : 23,
    '1900-10-31' : 21,    '1900-11-30' : 26,    '1900-12-31' : 23,
    })

#make plot
fig, ax = plt.subplots(figsize=(12, 7))
ax.bar(range(len(data)), data, color = 'maroon', width=0.5, zorder=3)

#ax.set_xticks uses a fixed locator
ax.set_xticks(range(len(data)))
#ax.set_xticklables uses a fixed formatter
ax.set_xticklabels(pd.to_datetime(data.index).strftime('%b'))

#format plot a little bit
ax.spines[['top','right']].set_visible(False)
ax.tick_params(axis='both', left=False, bottom=False, labelsize=13)
ax.grid(axis='y', color='gray', dashes=(8,3), alpha=0.5)

  • 条形图 x 轴刻度位置是 0 索引,而不是日期时间
  • 此解决方案适用于任何具有离散轴的图(例如条形图、历史图、热图等)
  • 类似于此answer,最简单的解决方案如下:
    • 如果 str 列已经存在则跳到第 3 步
    1. 使用 pd.to_datetime
    2. 'Birthday' 列转换为 datetime dtype
    3. 将缩写的月份名称提取到单独的列中
    4. 使用 pd.Categorical. The build-in calendar 模块排序列用于提供缩写月份名称的有序列表,或者可以手动输入该列表
    5. 使用 pandas.DataFrame.plot 绘制数据帧,它使用 matplotlib 作为默认后端
  • python 3.8.12pandas 1.3.4matplotlib 3.4.3
  • 中测试
import pandas as pd
import matplotlib.pyplot as plt
from calendar import month_abbr as ma  # ordered abbreviated month names

# convert the Birthday column to a datetime and extract only the date component
df.Birthday = pd.to_datetime(df.Birthday)

# create a month column
df['month'] = df.Birthday.dt.strftime('%b')

# convert the column to categorical and ordered
df.month = pd.Categorical(df.month, categories=ma[1:], ordered=True)

# plot the dataframe
ax = df.plot(kind='bar', x='month', y='Players', figsize=(12, 7), rot=0, legend=False)

  • 如果有很多重复的月份,必须聚合数据,然后使用 pandas.DataFrame.groupby 合并数据并聚合一些函数,如 .mean().sum()
dfg = df.groupby('month').Players.sum()

ax = dfg.plot(kind='bar', figsize=(12, 7), rot=0, legend=False)