时间是非常重要的,因为每一个人的时间都是一样的,对于所有人都是公平的,但是每一个人在每一个时间单位里创造的价值是不一样的。比如马云每个小时创造的价值可能是1万元,而普通工人可能是每小时10元,差距是非常大的,要比较这种差距,关键是在于时间的计量,只有在相同的时间才可以比较。又比如说在历史长河里,每一百年创造多少价值,也是需要通过时间轴来进行比较,才明显地看出历史的变化。又比如双11光棍节的销售额,如果要把近几年的时间画成曲线,也需要使用时间轴。可见,现实生活里,很多数据都与时间相关,并且沿着时间轴进行,要查看历史数据,才能明白过去情况,才能了解现在所处的位置,才能判断未来走向何处。其实,这就是人生的三大哲学问题,从何处来,现在位于何处,未来走向哪里去。由此看来,时间是非常重要的一条轴,观察很多数据都需要使用时间来表示,接着下来的内容就是非常重要的了,因为解决了大部分时间与众多数据关系的显示问题,也让大家明白时间的变化,各种因素是如何变化的。
解决上述的问题,首先就是怎么样把X轴的坐标改为日期显示,前面介绍的都是普通的数据,比如10分钟,10小时等等,这样的时间。现在需要按20/01/01来表2000年1月1日,又需要怎么样设置呢?因此,需要修改matplotlib的X轴坐标的表示方式,要改变它的格式,接着要改变画图的方式,让时间与数据对应的关系改变。
使用文字来描述比较困难的,还是先来看一下例子的结果:
从上图看到X轴是日期表示,它是从2000年1月1日开始,直到2021年1月1日,刚好一年的时间,在一年时间数据的变化情况。在这个例子里,Y轴的数据是采用随机生成的,每次运行的数据会不一样,因此显示的图也不一样,如果你运行代码后,发现图与本文里的不一样,不要见怪。要实现这样日期显示,又需要我们去做什么样的工作才可以呢?因为matplotlib默认的坐标显示,不是日期方式的,因此需要做多一些工作。
接着下来详细地解析一下例子的代码:
import matplotlib.dates as mdates
这行代码导入matplotlib日期处理模块,它的内容比较多,包含的内容如下图:
matplotlib.dates模块提供了复杂的日期显示功能,支持python里时间库datetime和常用的时间工具库dateutil。matplotlib提供的时间表示,是采用浮点数的方式来表示,表示从1970年1月1日0点开始的时间段。比如1970年1月1日 6点,用浮点数表示为0.25天。由于格式化对象使用datetime.datetime对象来表示,因此日期只能表示从0001年到9999年。如果按微秒来表示,只能表示70年范围左右。如果按20微秒的尺度来表示,就可以到9999年左右。如果想改变表示的精度,可以通过dates.set_epoch 或 rcParams[“dates.epoch”]来设置。这个库的内容比较多,后面再介绍其它内容。
import datetime
这行代码是导入python的日期表示模块,由于matplotlib支持日期显示模块。同时datetime模块也是比较常用的模块,对于python开发人员来说,这个模块是必须学习的,也是使用比较熟悉的。
host.xaxis.set_major_formatter(mdates.DateFormatter("%y/%m/%d"))
这行代码是设置X轴主刻度显示的格式,也就是说把浮点数表示的时间按字符串”%y/%m/%d”的格式化,相当于年/月/日的表示方式。在这里使用mdates.DateFormatter,它是一个类定义:
class matplotlib.dates.DateFormatter(fmt, tz=None)
这个类主要使用strftime的格式字符串来格化时间为日期表示。如果对strftime不太了解,可以参考下面的连接:
https://docs.python.org/3/library/datetime.html#datetime.datetime.strftime
具体格式是这样表示:
python中时间日期格式化符号:
- %y 两位数的年份表示(00-99)
-
%Y 四位数的年份表示(000-9999)
-
%m 月份(01-12)
-
%d 月内中的一天(0-31)
-
%H 24小时制小时数(0-23)
-
%I 12小时制小时数(01-12)
-
%M 分钟数(00=59)
-
%S 秒(00-59)
-
%a 本地简化星期名称
-
%A 本地完整星期名称
-
%b 本地简化的月份名称
-
%B 本地完整的月份名称
-
%c 本地相应的日期表示和时间表示
-
%j 年内的一天(001-366)
-
%p 本地A.M.或P.M.的等价符
-
%U 一年中的星期数(00-53)星期天为星期的开始
-
%w 星期(0-6),星期天为星期的开始
-
%W 一年中的星期数(00-53)星期一为星期的开始
-
%x 本地相应的日期表示
-
%X 本地相应的时间表示
-
%Z 当前时区的名称
-
%% %号本身
因此%y/%m/%d就是表示两位年份,月份,月内中的一天。
host.xaxis.set_major_formatter
,这个函数是把格式化的对象设置到主刻度里,它的定义如下:
Axis.set_major_formatter(self, formatter)
其中参数formatter可以是一个日期格式表示字符串,也可以一个函数。
host.xaxis.set_minor_locator(mdates.MonthLocator())
这行代码主要设置次要刻度的表示,按照月份来表示。如果不设置这行代码,就会显示如下:
如果设置了,显示为这样:
由此可见,多了次要刻度来表示中间不显示的月份,比如2月、4月等等。
host.tick_params(axis = "both", direction = "out", labelsize = 10)
这行代码是设置坐标轴上的刻度线的方向,其中参数axis = “both”是表示设置X轴和Y轴,两条轴都同时设置;参数direction = “out”表示刻度线从坐标轴指向哪里,这里使用out是表示从图像指向外面,如果设置为in表示从外面指向图像。参数labelsize = 10是表示设置坐标轴显示刻度值的字体大小。
date1 = datetime.date(2020, 1, 1)
date2 = datetime.date(2021, 1, 1)
delta = datetime.timedelta(days = 5)
dates = mdates.drange(date1, date2, delta)
print(dates)
这段代码是表示设置日期的范围,其中mdates.drange函数是表示返回从开始日期到结束日间的浮点数表示的日期列表,比如这里返回如下:
[737425. 737430. 737435. 737440. 737445. 737450. 737455. 737460. 737465.
\737470. 737475. 737480. 737485. 737490. 737495. 737500. 737505. 737510.
\737515. 737520. 737525. 737530. 737535. 737540. 737545. 737550. 737555.
\737560. 737565. 737570. 737575. 737580. 737585. 737590. 737595. 737600.
\737605. 737610. 737615. 737620. 737625. 737630. 737635. 737640. 737645.
\737650. 737655. 737660. 737665. 737670. 737675. 737680. 737685. 737690.
\737695. 737700. 737705. 737710. 737715. 737720. 737725. 737730. 737735.
\737740. 737745. 737750. 737755. 737760. 737765. 737770. 737775. 737780.
\737785. 737790.]
后面就可以把这个列表当作X轴的坐标。
y = np.random.normal(100, 15, len(dates))
这行代码是使用正态分布的随机函数生成len(dates)个数据。
host.plot_date(dates, y, 'b-', alpha = 0.7)
这行代码是把随机生成的数据放到Y轴,把日期放到X轴进行绘图,曲线的颜色为蓝色,透明度为0.7。
fig.autofmt_xdate()
这行代码是把X轴的日期自适应地调整显示,否则日期会盖住X轴,或者刻度线。当调用这个函数之后,可以把日期按最合适的方式调整,比如日期倾斜一定角度显示。
到这里就把整个日期的代码学习完成了,下面把整个完整的代码如下:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
#
fig, host = plt.subplots() #创建子图
host.grid(False)
#
host.xaxis.set_major_formatter(mdates.DateFormatter("%y/%m/%d"))
host.xaxis.set_minor_locator(mdates.MonthLocator())
host.tick_params(axis = "both", direction = "out", labelsize = 10)
date1 = datetime.date(2020, 1, 1)
date2 = datetime.date(2021, 1, 1)
delta = datetime.timedelta(days = 5)
dates = mdates.drange(date1, date2, delta)
print(dates)
y = np.random.normal(100, 15, len(dates))
host.plot_date(dates, y, 'b-', alpha = 0.7)
fig.autofmt_xdate()
plt.tight_layout()
plt.show()