需求
上面是客户给的样图,从上面的样图中我们可以总结出如下需求:
- 绘图样式包含散点图和折线图;
- 绘图包含虚线网格;
- 绘图包含图例,且字体样式是斜体;
- 有一个垂直颜色带;
- 下方的刻度线标签替换成日期;
实现
第一步,使用 pandas 读取数据,读取完毕之后直接调用 plot
方法进行绘图,对数据进行初步探查;
相比于样图,我们缺少了图例、网格、颜色带和散点图(客户说可以不做)。接下来针对需求进一步分析:
网格
这个的需求肯定是调用 Axes.grid()
方法进行实现,注意它的线形是 -.
;颜色是灰色(gray);
图例
调用 Axes.legend()
方法进行实现,这里需要注意一下,legend()
方法并没有提供 fontstyle
这个关键字参数,该方法只支持调整字号,并不支持设置字体样式,所以我们得另辟蹊径,columns = [f'${i}$' for i in columns]
这是我的实现方法,通过将正常字符转换成 Latex 字符的方式完成图例文字的斜体样式,由于我们自定义了图例文字,那么就必须传递 handler,由于客户给的数据只绘制了折线图,所以可以调用 Axes.lines
方法获得画布中所有的 Line2D 实例,这就是我们需要的 handler。最后如果不传递 ncols
这个关键字参数,那么所有的图例会被放在一列,因此还需要设置 ncols=3
,图例默认的摆放位置是 best
,这与需求不符,因此我们还要传递 loc='lower center'
进行更改。
颜色带
第一反应这个需求的实现肯定使用区域填充,直接调用 Axes.fill_between()
方法进行区域填充即可。填充的颜色使用的是 skyblue
,建议大家尽量用字符串表示颜色,这样看起来更加直观,颜色带的范围可以通过全局变量颜色带宽度进行控制。
其他
最后就设置一下轴标签和文字大小就行了。完整的代码如下:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 默认带状图颜色
DEFAULT_BETWEEN_COLOR = "skyblue"
# 默认抽样点数
DEFAULT_SAMPLE = 4
# 默认颜色带范围
DEFAULT_SAMPLE_SIZE = 1
# 默认Y轴标签
DEFAULT_TITLE = "NDVI"
df = pd.read_csv("pfree.csv", index_col=0)
columns = df.columns
columns = [f'${i}$' for i in columns]
M, N = df.shape
df.plot()
# 获取最大值
df_max = df.max().max()
# 获取最小值
df_min = df.min().min()
# 获取Axes对象
axes = plt.gca()
# 画网格
axes.grid(True, ls='-.', color='gray')
handler = axes.lines
# 画图例
axes.legend(loc='lower center', ncols=3, fontsize=10, handles=handler, labels=columns)
# 画文本
between_lines = [(i, i + DEFAULT_SAMPLE_SIZE) for i in range(1, M, DEFAULT_SAMPLE)]
for lines in between_lines:
x1 = lines[0]
x2 = lines[1]
r = np.linspace(x1, x2, 1000)
# 画带状图
axes.fill_between(r, 0, 0.5,
color=f'{DEFAULT_BETWEEN_COLOR}', alpha=0.3)
# 设置Y轴显示范围
axes.set_ylim([0, 0.419])
# 设置Y轴标签
axes.set_ylabel(DEFAULT_TITLE, fontsize=18)
plt.show()
画图效果如下:
文中难免会出现一些描述不当之处(尽管我已反复检查多次),欢迎在留言区指正,相关的知识点也可进行分享,希望大家都能有所收获!!