如何在matplotlib中禁用日期插值?

时间:2019-01-20 15:21:04

标签: python pandas dataframe matplotlib

尽管尝试使用SO和Matplotlib文档中提供的一些解决方案,但我仍然无法禁用Matplotlib在x轴上创建周末日期的功能。

正如您在下面看到的那样,它向x轴添加了不在原始Pandas列中的日期。

enter image description here

我正在使用我的数据进行绘图(注释行无法实现我的目标):

fig, ax1 = plt.subplots()

x_axis = df.index.values
ax1.plot(x_axis, df['MP'], color='k')
ax2 = ax1.twinx()
ax2.plot(x_axis, df['R'], color='r')

# plt.xticks(np.arange(len(x_axis)), x_axis)
# fig.autofmt_xdate()
# ax1.fmt_xdata = mdates.DateFormatter('%Y-%m-%d')

fig.tight_layout()
plt.show()

下面是我的Pandas数据框的示例,日期作为索引:

2019-01-09  1.007042  2585.898714  4.052480e+09  19.980000  12.07     1
2019-01-10  1.007465  2581.828491  3.704500e+09  19.500000  19.74     1
2019-01-11  1.007154  2588.605258  3.434490e+09  18.190001  18.68     1
2019-01-14  1.008560  2582.151225  3.664450e+09  19.070000  14.27     1

我发现一些建议包括自定义代码herehere,但是尽管我没有发现错误,但该情节却缺少我的第二个系列。

关于如何在matplotlib中禁用日期插值的任何建议?

3 个答案:

答案 0 :(得分:2)

matplotlib网站recommends creating a custom formatter class。此类将包含告诉轴标签如果日期为周末不显示任何内容的逻辑。这是一个示例,该示例使用我根据所附图像中的2018年数据构建的数据框:

df = pd.DataFrame(
data = {
 "Col 1" : [1.000325, 1.000807, 1.001207, 1.000355, 1.001512, 1.003237, 1.000979],
 "MP": [2743.002071, 2754.011543, 2746.121450, 2760.169848, 2780.756857, 2793.953050, 2792.675162],
 "Col 3": [3.242650e+09, 3.453480e+09, 3.576350e+09, 3.641320e+09, 3.573970e+09, 3.573970e+09, 4.325970e+09], 
 "Col 4": [9.520000, 10.080000, 9.820000, 9.880000, 10.160000, 10.160000, 11.660000],
 "Col 5": [5.04, 5.62, 5.29, 6.58, 8.32, 9.57, 9.53],
 "R": [0,0,0,0,0,1,1]
}, 
index=['2018-01-08', '2018-01-09', '2018-01-10', '2018-01-11',
       '2018-01-12', '2018-01-15', '2018-01-16'])
  1. 将日期从索引移动到自己的列:
df = df.reset_index().rename({'index': 'Date'}, axis=1, copy=False)
df['Date'] = pd.to_datetime(df['Date'])
  1. 创建自定义格式化程序类:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import Formatter
%config InlineBackend.figure_format = 'retina' # Get nicer looking graphs for retina displays

class CustomFormatter(Formatter):
    def __init__(self, dates, fmt='%Y-%m-%d'):
        self.dates = dates
        self.fmt = fmt

    def __call__(self, x, pos=0):
        'Return the label for time x at position pos'
        ind = int(np.round(x))
        if ind >= len(self.dates) or ind < 0:
            return ''

        return self.dates[ind].strftime(self.fmt)
  1. 现在让我们来绘制MPR系列。请注意我们称为自定义格式程序的行:
formatter = CustomFormatter(df['Date'])

fig, ax1 = plt.subplots()
ax1.xaxis.set_major_formatter(formatter)
ax1.plot(np.arange(len(df)), df['MP'], color='k')
ax2 = ax1.twinx()
ax2.plot(np.arange(len(df)), df['R'], color='r')
fig.autofmt_xdate()
fig.tight_layout()
plt.show()

上面的代码输出此图: Output graph

现在,x轴上没有显示周末日期,例如2018-01-13。

答案 1 :(得分:1)

如果要避免在数据集的每个点之间插值matplotlib的事实,则可以利用以下事实:matplotlib每次{{1}时都会绘制一个新的线段}。使用Pandas可以很容易地在np.NaN中插入np.NaN

pd.Dataframe.asfreq()

enter image description here

答案 2 :(得分:1)

如果您只是不想显示周末,而是希望图形仍然正确缩放,matplotlibmatplotlib.mdates中具有内置功能。具体来说,WeekdayLocator可以单手解决这个问题。这是一个单一的解决方案(其余只是构造数据进行测试)。请注意,无论数据是否包含周末,这都可行:

import matplotlib.pyplot as plt
import datetime
import numpy as np
import matplotlib.dates as mdates
from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU

DT_FORMAT="%Y-%m-%d"

if __name__ == "__main__":
    N = 14
    #Fake data
    x =  list(zip([2018]*N, [5]*N, list(range(1,N+1))))
    x = [datetime.datetime(*y) for y in x]
    x = [y for y in x if y.weekday() < 5]
    random_walk_steps = 2 * np.random.randint(0, 6, len(x)) - 3
    random_walk = np.cumsum(random_walk_steps)
    y = np.arange(len(x)) + random_walk

    # Make a figure and plot everything
    fig, ax = plt.subplots()
    ax.plot(x, y)

    ### HERE IS THE BIT THAT ANSWERS THE QUESTION
    ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=(MO, TU, WE, TH, FR)))
    ax.xaxis.set_major_formatter(mdates.DateFormatter(DT_FORMAT))

    # plot stuff
    fig.autofmt_xdate()
    plt.tight_layout()
    plt.show()

enter image description here