在本文中,我想分享我面临的挑战(和解决方案!
最近,我的任务是开发基于 Python 的工作流,并为我的雇主开发一篇文章。工作流涉及生成一些与技术分析相关的图表,本文涉及绘制一些波动曲面和各种曲线。
作为一个对Python相当新的人,以前从未真正使用过Matplotlib,这带来了相当的挑战。
当然,我读过几篇关于 Matplotlib 的文章/教程,但通常这些文章/教程非常”原子”,每个文章都侧重于各个功能位,而不是如何将多个功能组合到一个可呈现的图表中。或者,他们使用不同的方法/接口来实现类似的最终目标 ,从而更难组合代码的狙击。这些功能都未涵盖我想应用的所有不同功能,因此我不得不从多个来源收集提示和指导,只是为了使一个图表看起来漂亮。
我必须创建的每个图表都提出了一个略有不同的挑战,这意味着更多的搜索和更多的测试代码段。因此,我承诺将记录所有挑战和解决方案,以帮助处于类似情况的其他人,本文是这一承诺的结果。我希望你发现它有趣和有用…
美学第一
你可以想象,我的大部分挑战都是围绕我的图表的美学。对于我的技术分析工作流,我需要复制一些图表,这些图表可用于我的雇主的桌面应用程序,它们看起来比 Matplotlib 默认生成的”白色背景上的黑轴“更好。
桌面应用程序生成一些非常现代的外观图表与黑色/木炭背景和对比色线图:
现在,很显然,我无法复制那些已经进入这些工作的时间和抛光时间——但我确实至少想在一定程度上复制这种外观。因此,第一个挑战是使默认的 Matplotlib 内容如下所示:
xxxxxxx
指数2plt.图(x,关闭标签="关闭")
3plt.图(x,sma14,标签="SMA 14")
4plt.图(x,sma200,标签="SMA 200")
5plt.显示()
收盘价是我的收盘价数据和sma14和sma200代表我的短期和长期移动平均线数据。
需要修复的一些显而易见的事情:
- 更改背景和前景颜色
- 使图表变大
- 标记我的行图
- 标题图表
我以为我可以调用类似以下内容来更改背景颜色 - 但它似乎不是那么简单set_facecolor("黑色")"数据朗="文本/x-python"*
xxxxxxx
plt.set_facecolor("黑色")
相反,我不得不单独设置图形和斧头颜色(其中'0.25'是一个灰色阴影,我非常喜欢):
xxxxxxx
rcParams="图.面色"= "0.25"2plt.rcParams="轴.面色""0.25"
然后我发现我需要使用子图调用单独访问图形和坐标轴(以便更改刻度标记的颜色)。在此过程中,我发现我可以将无花果大小和面彩卷到相同的子图访问调用中 - 保存几行代码:
Python
xxxxxxx
11指数2无花果axplt.子图(面色="0.25",无花果大小=(28,8))28
3ax.set_facecolor('0.25')斧 。图(x,关闭标签='关闭',颜色='y')
4ax.图(x,sma14,标签="SMA 14"颜色='g')
5ax.图(x,sma200,标签="SMA 200",颜色="tab:紫色"ax.tick_params(轴='两个'颜色="w"标签大小=20)
6ylabel("关闭",颜色="y")7plt.图例(loc="上部中心",字体大小="x 大")
8plt.标题(f"简单移动平均: [ric]",颜色='w')
9plt.显示()
plt.subplots()调用返回封闭图(容器)和坐标轴,以便我可以单独与每个图形进行交互,而这样做时,我能够设置图形的大小和颜色。
此外,我做了以下
- 调用ax.set_facecolor()设置轴(绘图区域)颜色
- 通过添加 y_黄色、g_绿色和"tab:紫色"(来自 Tableau 调色板)的"颜色"参数,为每行图着色
- ax.tick_params()将两个轴上的刻度值的颜色从默认的黑色更改为更清晰的白色,并使字体变大一些
- plt.legend()在一个漂亮的小面板中显示实际的线条图标签
- 图表标题的 plt.title()
这一切让我更接近我正在寻找的更漂亮的图表:
在这一点上,我已经测试与
每日数据间隔,并认为事情看起来相当不错。然后,我测试与
每小时的数据间隔,并没有留下深刻的印象,我看到:
后来,我计算出,我可以使用numpy.arange函数来生成一些均匀间隔的数据——这些数据效果很好,但我的x轴不再显示日期。因此,我添加了以下自定义Formatter,以将日期还原到 x 轴。
Python
xxxxxxx
11类MyFormatter(物质):
2def__init__(自日期fmt='%Y-%m-%d'):
3自我
1px;"•自我。fmt = fmdef__call__ __call__(自, x, pos=0):
5'返回日期 x 在位置位置'
6indint(圆形(x)
7如果ind>=len(自我.日期或ind<0返回''
8返回自我。日期[ind]斯特夫时间(自我)。fmt)
然后,我将MyFormatter作为最终绘图代码的一部分,如下所示:
ax.plot(np.arange(len(x),sma200,标签="SMA 200",颜色="tab:紫色")Python
ax.tick_params(轴='两个',颜色='w',标签大小=20)
图autofmt_xdate()
plt.y 标签("关闭",颜色\y')
plt.legend(loc='上部中心',字体大小="x-大")
plt.title(f"简单移动平均: [ric]",颜色=w')
plt.show()"数据朗="文本/x-python"|xxxxxxx
1141x关闭。索引
2无花果axplt
25',无花果大小*(28 ,8))28
3ax.set_facecolor('0.25')
4物质MyFormatter(x)
5ax.x轴.set_major_formatter(物质)
6ax.图(np.范围(len(x)),贴标签="关闭",颜色='y')
7ax.图(np.范围(len(x)),sma14,标签="SMA 14"颜色='g')
8图(np.范围(len(x)),sma200,标签="SMA 200",颜色="tab:紫色"9ax.tick_params(轴='两个'颜色="w"标签大小=20)
10无花果.autofmt_xdate()
11plt.ylabel("关闭",颜色="y")
12plt.图例(loc="上部中心",字体大小="x 大")
13plt.标题(f"简单移动平均: [ric]",颜色='w')
14显示()我还添加了图autofmat_xdate()来旋转 x 轴标签并避免重叠。最终结果是具有均匀间隔日期标签的更平滑的绘图:
堆叠图表
对于简单移动平均线图,在与短线和长移动平均线相同的图上显示收盘价线是有意义的 - 将移动平均线与收盘价进行对比。
但是,对于接下来的两个图表,这并不理想-我真的需要将线条作为单独的绘图显示-尽管共享相同的 x 轴。换句话说,我想将两个图表"堆叠"在彼此之上。
首先,我试图创建两个图表并将其定位在彼此之上 -但图表之间的间隙太大,并且 x 轴不必要地重复。
然后,我遇到了 GridSpec 类,该类允许用户"指定网格的几何体,其中将放置一个子图"*听起来完美!
使用 GridSpec I 创建了包含 2 行和单个列的网格,然后将子图添加到每行
GridSpec(2,1)= 第 0 行的收盘价图表
axc = 无花果add_subplot(gs1[0])
axc.plot(np.arange(len(关闭.索引),关闭)* 第 1 行的 RSI 图表
斧子 = 无花果add_subplot(gs1[1])
axr.plot(np.arange(len(rsi.index)),rsi.value,color_'b')*最小化行之间的间隙
gs1.update(wspace=0.025,hspace=0.0)plt.show()"数据-朗="文本/x-python"*xxxxxxx
11• 创建 2(行) x 1(col) 网格
2gs1网格规格。GridSpec(21) = 第0 行的收盘价图表
3add_subplot(gs1=0|)4axc.图(np.(lenlen(关闭)索引关闭)= 第 1 行的 RSI 图表
5斧花果。add_subplot(gs1=1+)
6斧。图(np.(lenlen(rsi.索引rsi.值,颜色='b')= 最小化行之间的间隙
7gs1.更新(wspace=0.025hspace=0.0)plt。显示()
一旦我添加标签的附加内容,勾选参数,轴格式等,我结束了以下: