Matplotlib 可视化之箭头与标注的高级应用
時(shí)間線是按時(shí)間順序顯示的事件列表。它通常是一個(gè)圖形設(shè)計(jì),顯示一個(gè)長條,標(biāo)有與之平行的日期,通常是同時(shí)期的事件。
A_New_Chart_of_History_color?來源:維基百科
時(shí)間線可以使用任何合適的比例來表示時(shí)間,適合主題和數(shù)據(jù);許多人使用線性刻度,其中一個(gè)距離單位等于設(shè)定的時(shí)間量。此時(shí)間刻度取決于時(shí)間軸中的事件。
Matplotlib最初是由John D. Hunter編寫的,第一個(gè)公開版本于2003年發(fā)布。在2012年8月John Hunter去世前不久,Michael Droettboom被提名為matplotlib的首席開發(fā)者,2014年Thomas Caswell加入,他現(xiàn)在(2021年)是首席開發(fā)者。最新的版本是3.4(撰寫本文時(shí)),并且只支持Python 3,而2.2版本是一個(gè)長期支持的版本,兼容Python 2和Python 3。
Timeline繪圖
時(shí)間線
繪圖步驟
創(chuàng)建畫布、設(shè)置字體大小、設(shè)置x、y坐標(biāo)軸及標(biāo)簽
繪制直線圖、空心的散點(diǎn)圖
隱藏x、y坐標(biāo)軸
代碼
#?step1 fig?=?plt.figure(figsize=(15,?6)) ax?=?fig.add_subplot(111,?xlim=(2002.5,?2021.5),?ylim=(0,?6.5),?yticks=([])) ax.tick_params("x",?labelsize="x-small",?which="major") ax.set_xticks(np.arange(2003,?2022,?2)) #?step2 plt.plot([2002.5,?2021.5],?[0,?0],?color="black",?linewidth=1.0,?clip_on=False) X?=?np.arange(2003,?2022) Y?=?np.zeros(len(X)) plt.scatter(X,Y,s=100,?????????#?散點(diǎn)大小linewidth=1.0,?#?散點(diǎn)線寬zorder=10,?????#?見注解clip_on=False,?#?是否設(shè)置兩個(gè)線相交時(shí)的剪輯edgecolor="black",?#?散點(diǎn)的邊緣顏色facecolor="white",?#?散點(diǎn)的填充顏色 ) #?step3 ax.spines["right"].set_visible(False) ax.spines["left"].set_visible(False) ax.spines["top"].set_visible(False) ax.spines["bottom"].set_visible(False)注解:
Matplotlib 的 zorder 屬性決定了物體與前景的距離。zorder 值較小的對(duì)象出現(xiàn)在更靠近背景的位置,而具有較大值的對(duì)象出現(xiàn)在更靠近前面的位置。例如,如果我正在制作一個(gè)帶有線圖的散點(diǎn)圖,我可以通過增加它的 zorder 來將線向前移動(dòng)。
標(biāo)注
要掌握時(shí)間軸圖繪制,需要先了解 Matplotlib 中的標(biāo)注。標(biāo)注分為基本標(biāo)注和高級(jí)標(biāo)注。
基本標(biāo)注:
使用annotate()函數(shù),其中由參數(shù)xy表示的標(biāo)注位置和xytext的文本位置,這兩個(gè)參數(shù)都是(x, y)元組。高級(jí)標(biāo)注:
使用框和文本來標(biāo)注,在pyplot模塊(或Axes類的text方法)中的text()函數(shù)接受bbox關(guān)鍵字參數(shù),在文本周圍繪制一個(gè)框。
關(guān)鍵點(diǎn):箭頭及文本,首先學(xué)習(xí)下箭頭??如何繪制。
箭頭風(fēng)格
Matplotlib 里面畫箭頭通常比較困難,推薦使用 plt.annotate() 函數(shù)。這個(gè)函數(shù)既可以創(chuàng)建文字,也可以創(chuàng)建箭頭,而且它創(chuàng)建的箭頭能夠進(jìn)行非常靈活的配置。
箭頭的風(fēng)格是通過 arrowprops 字典控制的,里面有許多可用的選項(xiàng)。由于這些選項(xiàng)在 Matplotlib 的官方文檔中都有非常詳細(xì)的介紹,為了方便閱讀,這里給大家列出一些常用的參數(shù)及其設(shè)置值。
Axes.annotate(self,?s,?xy,?*args,?**kwargs)主要參數(shù):
s:是注釋的文本。
xy:是要注釋的點(diǎn)(x, y)。
xytext:是可選參數(shù)。它是放置文本的位置(x, y)。
xycoords:被注釋點(diǎn)的坐標(biāo)系屬性,允許輸入的值如下
| 'figure points' | 距離圖形左下角的點(diǎn)數(shù)量 |
| 'figure pixels' | 距離圖形左下角的像素?cái)?shù)量 |
| 'figure fraction' | 0,0 是圖形左下角,1,1 是右上角 |
| 'axes points' | 距離軸域左下角的點(diǎn)數(shù)量 |
| 'axes pixels' | 距離軸域左下角的像素?cái)?shù)量 |
| 'axes fraction' | 0,0 是軸域左下角,1,1 是右上角 |
| 'data' | 使用軸域數(shù)據(jù)坐標(biāo)系 |
textcoords:注釋文本的坐標(biāo)系屬性,默認(rèn)與xycoords屬性值相同,也可設(shè)為不同的值。除了允許輸入xycoords的屬性值,還允許輸入以下兩種:
| ''offset points'' | 與xy值的偏移量(以磅為單位) |
| ''offset points'' | 從xy值偏移(以像素為單位) |
arrowprops:箭頭的樣式,dict(字典)型數(shù)據(jù),如果該屬性非空,則會(huì)在注釋文本和被注釋點(diǎn)之間畫一個(gè)箭頭。如果不設(shè)置'arrowstyle' 關(guān)鍵字,則允許包含以下關(guān)鍵字:
| width | 箭頭的寬度(單位是點(diǎn)) |
| headwidth | 箭頭頭部的寬度(點(diǎn)) |
| headlength | 箭頭頭部的長度(點(diǎn)) |
| shrink | 箭頭兩端收縮的百分比(占總長) |
| ? | 任何 matplotlib.patches.FancyArrowPatch中的關(guān)鍵字 |
FancyArrowPatch的關(guān)鍵字包括:
| arrowstyle | 箭頭的樣式 |
| connectionstyle | 連接線的樣式 |
| relpos | 箭頭起始點(diǎn)相對(duì)注釋文本的位置,默認(rèn)為 (0.5, 0.5),即文本的中心,(0,0)表示左下角,(1,1)表示右上角 |
| patchA | 箭頭起點(diǎn)處的圖形(matplotlib.patches對(duì)象),默認(rèn)是注釋文字框 |
| patchB | 箭頭終點(diǎn)處的圖形(matplotlib.patches對(duì)象),默認(rèn)為空 |
| shrinkA | 箭頭起點(diǎn)的縮進(jìn)點(diǎn)數(shù),默認(rèn)為2 |
| shrinkB | 箭頭終點(diǎn)的縮進(jìn)點(diǎn)數(shù),默認(rèn)為2 |
| mutation_scale | default is text size (in points) |
| mutation_aspect | default is 1. |
| ? | any key for `matplotlib.patches.PathPatch`[1] |
annotation_clip :
布爾值,可選參數(shù),默認(rèn)為空。設(shè)為True時(shí),只有被注釋點(diǎn)在子圖區(qū)內(nèi)時(shí)才繪制注釋;設(shè)為False時(shí),無論被注釋點(diǎn)在哪里都繪制注釋。僅當(dāng)xycoords為 'data' 時(shí),默認(rèn)值空相當(dāng)于True。
箭頭
箭頭的繪制需要幾個(gè)步驟:
① 創(chuàng)建兩個(gè)點(diǎn)之間的連接路徑。這由connectionstyle鍵值控制。
② 如果提供了patch對(duì)象(patchA和patchB),則會(huì)剪切路徑以避開該patch。
③ 路徑進(jìn)一步由提供的像素總量來縮小(shirnkA&shrinkB)
④ 路徑轉(zhuǎn)換為箭頭patch,由arrowstyle鍵值控制。
連接路徑
兩個(gè)點(diǎn)之間的連接路徑的創(chuàng)建由connectionstyle鍵控制,并且可用以下樣式。
| angle | angleA=90,angleB=0,rad=0.0 |
| angle3 | angleA=90,angleB=0 |
| arc | angleA=0,angleB=0,armA=None,armB=None,rad=0.0 |
| arc3 | rad=0.0 |
| bar | armA=0.0,armB=0.0,fraction=0.3,angle=None |
注意,angle3和arc3中的3意味著所得到的路徑是二次樣條段(三個(gè)控制點(diǎn))。如下面將討論的,當(dāng)連接路徑是二次樣條時(shí),可以使用一些箭頭樣式選項(xiàng)。
ax.annotate(arrowprops=dict(connectionstyle=connectionstyle)在函數(shù)ax.annotate()中的連接路徑的參數(shù)arrowprops,而實(shí)際控制箭頭樣式的參數(shù)是connectionstyle,通過設(shè)置不同的connectionstyle以改變不同的箭頭路徑樣式。
例如我們?cè)O(shè)置如下參數(shù)connectionstyle具體值,并繪制出如下樣式。
"angle3,angleA=90,angleB=0" "angle3,angleA=0,angleB=90" "arc3,rad=0." "arc3,rad=0.3" "arc3,rad=-0.3" "angle,angleA=-90,angleB=180,rad=0" "angle,angleA=-90,angleB=180,rad=5" "angle,angleA=-90,angleB=10,rad=5" "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0" "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5" "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0" "bar,fraction=0.3" "bar,fraction=-0.3" "bar,angle=180,fraction=-0.2"箭頭樣式
后根據(jù)給定的箭頭樣式將連接路徑(在剪切和收縮之后)變換為箭頭補(bǔ)丁。
在函數(shù)ax.annotate()中的箭頭樣式的參數(shù)arrowprops,而實(shí)際控制箭頭樣式的參數(shù)是arrowstyle,通過設(shè)置不同的arrowstyle以改變不同的箭頭樣式。
ax.annotate(arrowprops=dict(arrowstyle=stylenames)我們可以設(shè)置哪些arrowstyle參數(shù)呢?可以通過mpatches.ArrowStyle.get_styles()方法查看所有可以設(shè)置的樣式。
styles?=?mpatches.ArrowStyle.get_styles() print(styles.keys())dict_keys(['-', '<-', '->', '<->', '<|-','-|>', '<|-|>', ']-[', ']-', '-[','|-|', 'simple', 'fancy', 'wedge'])箭頭位置
xy(箭頭尖端)和 xytext 位置(文本位置)都以數(shù)據(jù)坐標(biāo)為單位。這兩個(gè)參數(shù)可以通過分別設(shè)置xycoords和textcoords來指定xy和xytext的坐標(biāo)系。
設(shè)置xy和xytext的坐標(biāo)系如下:
(3.2, 6.8) (2.0, 6.8) (4.2, 5.8) (2.0, 5.8) (4.2, 4.8) (3.4, 4.8) (3.2, 3.8) (3.2, 2.8)通過上述設(shè)置完成操作后,設(shè)置標(biāo)注函數(shù):
def?annotate(ax,?x,?y,?text,?fc="#ff7777",?y0=0):y?=?y?-?0.5ax.annotate("?"?+?text?+?"?",xy=(x,?y),xycoords="data",xytext=(0,?25),textcoords="offset?points",color="white",size="x-small",va="center",ha="center",weight="bold",bbox=dict(boxstyle="round",?fc=fc,?ec="none"),arrowprops=dict(arrowstyle="wedge,?tail_width=1.",?fc=fc,?ec="none",?patchA=None),?)plt.plot([x,?x],?[y,?y0],?color="black",?linestyle=":",?linewidth=0.75)并且通過上述函數(shù)繪制各個(gè)事件:
annotate(ax,?2021,?4,?"3.4") annotate(ax,?2020,?3,?"3.3") annotate(ax,?2019,?4,?"3.2") annotate(ax,?2019,?2,?"3.1") annotate(ax,?2018,?3,?"3.0",?y0=1.5) annotate(ax,?2018,?1,?"2.2",?fc="#777777") annotate(ax,?2017,?4,?"2.1",?y0=2.5) annotate(ax,?2017,?2,?"2.0") annotate(ax,?2015,?2,?"1.5") annotate(ax,?2014,?1,?"1.4") annotate(ax,?2013,?2,?"1.3") annotate(ax,?2012,?1,?"1.2") annotate(ax,?2011,?3,?"1.1",?y0=2.5) annotate(ax,?2011,?2,?"1.0") annotate(ax,?2009,?1,?"0.99") annotate(ax,?2003,?1,?"0.10")文本注釋
Axes.text(self,?x,?y,?s,?fontdict=None,?withdash=,?**kwargs)主要參數(shù):
x,y:表示坐標(biāo)值上的值
string:表示說明文字
fontsize:表示字體大小
verticalalignment or va:垂直對(duì)齊方式 ,參數(shù):[ 'center' |'top' | 'bottom' | 'baseline' ]
horizontalalignment or ha:水平對(duì)齊方式 ,參數(shù):[ 'center' |'right' |'left' ]
matplotlib.text.Text實(shí)例有各種屬性,可以通過關(guān)鍵字參數(shù)配置文本命令(例如,title(),xlabel()和text())。
你可以使用對(duì)齊參數(shù)horizontalalignment,verticalalignment和multialignment來布置文本。
horizontalalignment控制文本的x位置參數(shù)表示文本邊界框的左邊,中間或右邊。
verticalalignment控制文本的y位置參數(shù)表示文本邊界框的底部,中心或頂部。
multialignment,僅對(duì)于換行符分隔的字符串,控制不同的行是左,中還是右對(duì)齊。
這里是一個(gè)使用text()命令顯示各種對(duì)齊方式的例子。在整個(gè)代碼中使用transform = ax.transAxes,表示坐標(biāo)相對(duì)于軸邊界框給出,其中0,0是軸的左下角,1,1是右上角。
通過繪制兩個(gè)端點(diǎn)及橫線組合,繪制區(qū)間線段。
x0,?x1?=?2002.5,?2011.9 ax.plot([x0,?x1],?[5,?5],?color="black",?linewidth=1,?marker="|",?clip_on=False) ax.text((x0?+?x1)?/?2,?5.1,?"J.D.?Hunter",?ha="center",?va="bottom",?size="x-small")x0,?x1?=?2012.1,?2017.9 ax.plot([x0,?x1],?[5,?5],?color="black",?linewidth=1,?marker="|",?clip_on=False) ax.text((x0?+?x1)?/?2,?5.1,?"M.?Droettboom",?ha="center",?va="bottom",?size="x-small")x0,?x1?=?2014.1,?2021.5 ax.plot([x0,?x1?+?1],?[6,?6],?color="black",?linewidth=1,?marker="|") ax.text((x0?+?x1)?/?2,?6.1,?"T.?Caswell",?ha="center",?va="bottom",?size="x-small"參考資料
[1]
matplotlib.patches.PathPatch: https://matplotlib.org/api/_as_gen/matplotlib.patches.PathPatch.html#matplotlib.patches.PathPatch
[2]connectionstyle源碼: https://matplotlib.org/stable/gallery/userdemo/connectionstyle_demo.html
[3]fancyarrow_demo源碼: http://matplotlib.org/mpl_examples/pylab_examples/fancyarrow_demo.py
[4]annotation_demo源碼: https://matplotlib.org/stable/gallery/text_labels_and_annotations/annotation_demo.html
[5]Scientific Visualisation-Python & Matplotlib
END
各位伙伴們好,詹帥本帥搭建了一個(gè)個(gè)人博客和小程序,匯集各種干貨和資源,也方便大家閱讀,感興趣的小伙伴請(qǐng)移步小程序體驗(yàn)一下哦!(歡迎提建議)推薦閱讀
牛逼!Python常用數(shù)據(jù)類型的基本操作(長文系列第①篇)
牛逼!Python的判斷、循環(huán)和各種表達(dá)式(長文系列第②篇)
牛逼!Python函數(shù)和文件操作(長文系列第③篇)
牛逼!Python錯(cuò)誤、異常和模塊(長文系列第④篇)
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Matplotlib 可视化之箭头与标注的高级应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 好家伙,MacOS 新版本终于删掉自带
- 下一篇: VS Code,请还我文件!!!