Python 在同一轴上绘制多年数据时定义 xlim

Python defining xlim when when plotting multiple year data on same axis

我想在同一个轴上绘制几年的数据。 很有用,但我似乎无法定义 xlim。 MWE 是

import numpy as np
import pandas as pd
from datetime import datetime, date, timedelta

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as tkr

data15 = pd.DataFrame([1,2,3,4,5,6,7,8,9,10,11,12], index=pd.date_range(start='2015-01',end='2016-01',freq='M'), columns=['2015'])
data16 = pd.DataFrame([5,4,3,2,1], index=pd.date_range(start='2016-01',end='2016-06',freq='M'), columns=['2016'])

data15['month'] = data15.index.to_series().dt.strftime('%b')
data16['month'] = data16.index.to_series().dt.strftime('%b')

ax = data16.plot(x='month', y='2016')
ax = data15.plot(x='month', y='2015', ax=ax)

ax.xaxis.set_major_locator(mdates.DayLocator(interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b'))
plt.setp(ax.get_xticklabels()[::2], visible=False)

ax.set_xlim(data16.month[0], data16.month[-1])
plt.show()

不管我怎么改都只想显示前两个数据点xlim。我该如何解决这个问题?

没有set_xlim的图是

所以 ax.set_xlim(data16.month[0], data16.month[-1]) 行应该只显示 JanMay 之间的点。

目前还不清楚数据帧的条件是什么,但将 pandas matplotlib 便利包装器与 higher-end matplotlib 函数混合使用通常会产生问题。假设每个数据帧恰好存在一个每月数据点,您可以提取月份编号并使用月份名称重新标记 x-axis:

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

data15 = pd.DataFrame([1,2,3,4,5,6,7,8,9,10,11,12], index=pd.date_range(start='2015-01',end='2016-01',freq='M'), columns=['2015'])
data16 = pd.DataFrame([5,4,3,2,1], index=pd.date_range(start='2016-01',end='2016-06',freq='M'), columns=['2016'])

#generating column with month number
data15['month'] = data15.index.to_series().dt.month                                               
data16['month'] = data16.index.to_series().dt.month

fig, ax = plt.subplots()

ax.plot(data15['month'], data15['2015'], label="2015")
ax.plot(data16['month'], data16['2016'], label="2016")

#setting x-ticks 1-12 with corresponding month names
ax.set_xticks(range(1, 13), [calendar.month_abbr[i] for i in range(1, 13)])
ax.legend()

plt.show()

输出:

或者,您可以创建全部设置为任意年份相应月份的第一天的日期时间对象:

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

data15 = pd.DataFrame([1,2,3,4,5,6,7,8,9,10,11,12], index=pd.date_range(start='2015-01',end='2016-01',freq='M'), columns=['2015'])
data16 = pd.DataFrame([5,4,3,2,1], index=pd.date_range(start='2016-01',end='2016-06',freq='M'), columns=['2016'])

#generating datetime objects keeping only the month
#while setting day/year to arbitrary values so that the curves align
data15['month'] = data15.index + pd.offsets.DateOffset(day=1, year=2000)                                                
data16['month'] = data16.index + pd.offsets.DateOffset(day=1, year=2000)

fig, ax = plt.subplots()

ax.plot(data15['month'], data15['2015'], label="2015")
ax.plot(data16['month'], data16['2016'], label="2016")

#formatting monthly x-axis ticks showing only the month name
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter('%b'))
ax.legend()

plt.show()

输出看起来是一样的,但你仍然有 datetime 对象,尽管是任意年份和日期。

假设您可能想要比较多年,您可以将第一种方法嵌入到这样的函数中:

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

data15 = pd.DataFrame([1,2,3,4,5,6,7,8,9,10,11,12], index=pd.date_range(start='2015-01',end='2016-01',freq='M'), columns=['2015'])
data16 = pd.DataFrame([5,4,3,2,1], index=pd.date_range(start='2016-01',end='2016-06',freq='M'), columns=['2016'])

#collecting all dataframes to plot
plot_list = [data15, data16]

fig, ax = plt.subplots()

def plot_line(df):
    #this assumes that the data to plot will always be in the first column
    col = df.columns[0]
    ax.plot(df.index.to_series().dt.month, df[col], label=col)                                              

for item in plot_list:
    plot_line(item)

ax.set_xticks(range(1, 13), [calendar.month_abbr[i] for i in range(1, 13)])
ax.legend()

plt.show()