在本文中,我想分享我面临的挑战(和解决方案!
最近,我的任务是开发基于 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。显示()
一旦我添加标签的附加内容,勾选参数,轴格式等,我结束了以下:
![]()
请注意虚线"RSI 阈值"行位于 70 和 30 , 我添加了以下代码:
Python
xxxxxxx
11plt.斧林(y=70颜色='w',线形='-')
2斧林(y=30,颜色='w',线形='-'然后,我重用了上述所有技术来创建一个随机图,你可以看到下面:
我没有在这里包括上述图表的完整代码,以保持文章尽可能短,所以我将提供一个链接的完整源在末尾其他人已经创建了我需要的类型的一些基本绘图 - 但是,我不希望默认的 Matplotlib 外观:
我不喜欢颜色,轴标签的位置,也不喜欢Y轴刻度标签。我已经知道如何做颜色,刚刚离开滴答标签和斧头标签定位。
那么,为什么"到期时间"的 Y 轴刻度标有数值?因为对于此绘图类型,Matplotlib 库要求以"自 UTC 以来的天数" (例如 737600 = 2020 年 6 月 25 日) 表示日期。
最初,我试图找到一种以两种格式传递日期的方法,一种用于标记标签,另一种用于绘图 -在调用绘图函数时。然而,我很快意识到,我可以再次使用自定义的Formatter:
Python
xxxxxxx
11def format_date(x,位置=无):3进口垫片。日期作为日期返回日期。num2date(x)。稳时("%Y-%m-%d"
轴标签间距/位置可以通过标签板属性进行改进。因此,以下代码段:
Python
xxxxxxx
11轴(投影='3d')2ax.set_facecolor('0.25')
3ax.set_title("Vol Surface 为 : 大众",颜色='w')
4ax.set_xlabel("金钱",颜色='y',标签板=10)
5ax.set_ylabel("过期",颜色='y',标签板=15)
6ax.set_zlabel("波动",颜色="y")
7tick_params(轴='两个',颜色='w')ax.w_yaxis。set_major_formatter(刻度)。丰件 (format_date)8
9冲浪斧。plot_surface(X,Y,Zcmap=厘米.冷暖线宽=0反锯齿=假)plt。显示()
产生以下 - 我希望你会同意,看起来更有吸引力:
改进的波动性曲面,包括 Y 轴刻度和更整洁的轴标签的日期 有点作弊!
最后一个,我不得不承认是有点欺骗-可能有一个正确的方式做到这一点-但我的'修复'工作!
我不得不在给定时间段内绘制一个图表,其中有三个工具的数据png"数据-新="假"数据大小="38323"数据大小格式化="38.3 kB"数据类型="临时"数据 url="/存储/临时/13268271 -混乱-术语-图.png"src_"http://www.cheeli.com.cn/wp-内容/上传/2020/04/13268271-混乱-术语-情节.png"/]
英镑、欧元和瑞士法郎的略带古怪的期限结构图表 经过一番挖掘,发现英镑数据有2022年的额外数据点(欧元和瑞士法郎数据没有)。然而,由于我在英镑数据之前绘制了欧元数据,Matplotlib 造成了您上面看到的烂摊子。
那么,我是如何"修复"的呢?我刚刚首先绘制了 GBP 数据 - 给了我以下更整洁的输出:
我的"固定"术语结构图表(颜色交换 - 英镑为蓝色) 从中得到的启示是,在处理非相同的 x 轴值时,多行图的序列似乎很重要。我想,如果每个货币有不同的日期,我将不得不以某种方式填充/填写日期。
结束词
我确实有几个其他问题围绕创建和格式化这些图表 - 但这些与数据格式不太需要/希望它的方式 - 而不是 Matplotlib 问题有关。
所以,谢谢你的阅读,我希望你发现它有趣,如果不是完全有用!
完整源代码:
正如所承诺的,下面是我在上面使用的代码段背后的完整源代码的链接。您将需要各种许可证/帐户来运行它们 - 但是,我希望您可以解除相关的图表代码段,并将其与 Python 代码中的数据重用。 Comments are closed.