Python之Matplotlib文字與注釋的使用方法
可視化對于大家來說確實(shí)是有關(guān)的,因?yàn)榇_實(shí)是直觀的,每一組大數(shù)據(jù)如果可以用可視化進(jìn)行展示的話可以讓大家豁然開朗。但在另外一些場景中,輔之以少量的文字提示(textual cue)
和標(biāo)簽是必不可少的。雖然最基本的注釋(annotation)
類型可能只是坐標(biāo)軸標(biāo)題與圖標(biāo)題,但注釋可遠(yuǎn)遠(yuǎn)不止這些。讓我們可視化一些數(shù)據(jù),看看如何通過添加注釋來更恰當(dāng)?shù)乇磉_(dá)信息。
首先導(dǎo)入畫圖需要用到的一些函數(shù):
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd
1 案例:節(jié)假日對美國出生率的影響
數(shù)據(jù)可以在 https://github.com/jakevdp/data-CDCbirths 下載,數(shù)據(jù)類型如下:
用清洗方法處理數(shù)據(jù),然后畫出結(jié)果。
日均出生人數(shù)統(tǒng)計(jì)圖
births = pd.read_csv('births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax);
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax); plt.show()
為日均出生人數(shù)統(tǒng)計(jì)圖添加注釋
在用這樣的圖表達(dá)觀點(diǎn)時,如果可以在圖中增加一些注釋,就更能吸引讀者的注意了??梢酝ㄟ^ plt.text / ax.text
命令手動添加注釋,它們可以在具體的 x / y 坐標(biāo)點(diǎn)上放上文字
fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax) # 在圖上增加文字標(biāo)簽 style = dict(size=10, color='gray') ax.text('2012-1-1', 3950, "New Year's Day", **style) ax.text('2012-7-4', 4250, "Independence Day", ha='center', **style) ax.text('2012-9-4', 4850, "Labor Day", ha='center', **style) ax.text('2012-10-31', 4600, "Halloween", ha='right', **style) ax.text('2012-11-25', 4450, "Thanksgiving", ha='center', **style) ax.text('2012-12-25', 3850, "Christmas ", ha='right', **style) # 設(shè)置坐標(biāo)軸標(biāo)題 ax.set(title='USA births by day of year (1969-1988)', ylabel='average daily births') # 設(shè)置x軸刻度值,讓月份居中顯示 ax.xaxis.set_major_locator(mpl.dates.MonthLocator()) ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15)) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h'));
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax) # 在圖上增加文字標(biāo)簽 style = dict(size=10, color='gray') ax.text('2012-1-1', 3950, "New Year's Day", **style) ax.text('2012-7-4', 4250, "Independence Day", ha='center', **style) ax.text('2012-9-4', 4850, "Labor Day", ha='center', **style) ax.text('2012-10-31', 4600, "Halloween", ha='right', **style) ax.text('2012-11-25', 4450, "Thanksgiving", ha='center', **style) ax.text('2012-12-25', 3850, "Christmas ", ha='right', **style) # 設(shè)置坐標(biāo)軸標(biāo)題 ax.set(title='USA births by day of year (1969-1988)', ylabel='average daily births') # 設(shè)置x軸刻度值,讓月份居中顯示 ax.xaxis.set_major_locator(mpl.dates.MonthLocator()) ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15)) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h')); plt.show()
ax.text
方法需要一個 x 軸坐標(biāo)、一個 y 軸坐標(biāo)、一個字符串和一些可選參數(shù),比如文字的顏色、字號、風(fēng)格、對齊方式以及其他文字屬性。這里用了 ha='right'
與 ha='center'
,ha
是水平對齊方式(horizonal alignment
)的縮寫。關(guān)于配置參數(shù)的更多信息,請參考plt.text()
與 mpl.text.Text()
的程序文檔。
2 坐標(biāo)變換與文字位置
前面的示例將文字放在了目標(biāo)數(shù)據(jù)的位置上。但有時候可能需要將文字放在與數(shù)據(jù)無關(guān)的位置上,比如坐標(biāo)軸或者圖形中。在 Matplotlib 中,我們通過調(diào)整坐標(biāo)變換(transform)
來實(shí)現(xiàn)。
任何圖形顯示框架都需要一些變換坐標(biāo)系的機(jī)制。例如,當(dāng)一個位于 (x, y) = (1, 1)
位置的點(diǎn)需要以某種方式顯示在圖上特定的位置時,就需要用屏幕的像素來表示。用數(shù)學(xué)方法處理這種坐標(biāo)系變換很簡單,Matplotlib 有一組非常棒的工具可以實(shí)現(xiàn)類似功能(這些工具位于 matplotlib.transforms 子模塊
中)。
雖然一般用戶并不需要關(guān)心這些變換的細(xì)節(jié),但是了解這些知識對在圖上放置文字大有幫助。一共有三種解決這類問題的預(yù)定義變換方式。
- ax.transData 以數(shù)據(jù)為基準(zhǔn)的坐標(biāo)變換。
- ax.transAxes 以坐標(biāo)軸為基準(zhǔn)的坐標(biāo)變換(以坐標(biāo)軸維度為單位)。
- fig.transFigure 以圖形為基準(zhǔn)的坐標(biāo)變換(以圖形維度為單位)。
默認(rèn)情況下,上面的文字在各自的坐標(biāo)系中都是左對齊的。這三個字符串開頭的 . 字符基本就是對應(yīng)的坐標(biāo)位置。
transData
坐標(biāo)用 x 軸與 y 軸的標(biāo)簽作為數(shù)據(jù)坐標(biāo)。
transAxes
坐標(biāo)以坐標(biāo)軸(圖中白色矩形)左下角的位置為原點(diǎn),按坐標(biāo)軸尺寸的比例呈現(xiàn)坐標(biāo)。
transFigure
坐標(biāo)與之類似,不過是以圖形(圖中灰色矩形)左下角的位置為原點(diǎn),按圖形尺寸的比例呈現(xiàn)坐標(biāo)。
對比 Matplotlib 的三種坐標(biāo)系(1)
下面舉一個例子,用三種變換方式將文字畫在不同的位置:
fig, ax = plt.subplots(facecolor='lightgray') ax.axis([0, 10, 0, 10]) # 雖然transform=ax.transData是默認(rèn)值,但還是設(shè)置一下 ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData) ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes) ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure);
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(facecolor='lightgray') ax.axis([0, 10, 0, 10]) # 雖然transform=ax.transData是默認(rèn)值,但還是設(shè)置一下 ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData) ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes) ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure); plt.show()
對比 Matplotlib 的三種坐標(biāo)系(2)
需要注意的是,假如你改變了坐標(biāo)軸上下限,那么只有 transData 坐標(biāo)會受影響,其他坐標(biāo)系都不變
ax.set_xlim(0, 2) ax.set_ylim(-6, 6) fig
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(facecolor='lightgray') ax.axis([0, 10, 0, 10]) # 雖然transform=ax.transData是默認(rèn)值,但還是設(shè)置一下 ax.text(1, 5, ". Data: (1, 5)", transform=ax.transData) ax.text(0.5, 0.1, ". Axes: (0.5, 0.1)", transform=ax.transAxes) ax.text(0.2, 0.2, ". Figure: (0.2, 0.2)", transform=fig.transFigure); ax.set_xlim(0, 2) ax.set_ylim(-6, 6) fig plt.show()
如果你改變了坐標(biāo)軸上下限,那么就可以更清晰地看到剛剛所說的變化。
3 箭頭與注釋
除了刻度線和文字,簡單的箭頭也是一種有用的注釋標(biāo)簽。
在 Matplotlib 里面畫箭頭通常比你想象的要困難。雖然有一個 plt.arrow()
函數(shù)可以實(shí)現(xiàn)這個功能,但是我不推薦使用它,因?yàn)樗鼊?chuàng)建出的箭頭是 SVG 向量圖
對象,會隨著圖形分辨率的變化而改變,最終的結(jié)果可能完全不是用戶想要的。我要推薦的是 plt.annotate()
函數(shù)。這個函數(shù)既可以創(chuàng)建文字,也可以創(chuàng)建箭頭,而且它創(chuàng)建的箭頭能夠進(jìn)行非常靈活的配置。
圖形注釋
下面用 annotate 的一些配置選項(xiàng)來演示
fig, ax = plt.subplots() x = np.linspace(0, 20, 1000) ax.plot(x, np.cos(x)) ax.axis('equal') ax.annotate('local maximum', xy=(6.28, 1), xytext=(10, 4),arrowprops=dict(facecolor='black', shrink=0.05)) ax.annotate('local minimum', xy=(5 * np.pi, -1), xytext=(2, -6),arrowprops=dict(arrowstyle="->", connectionstyle="angle3,angleA=0,angleB=-90"));
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots() x = np.linspace(0, 20, 1000) ax.plot(x, np.cos(x)) ax.axis('equal') ax.annotate('local maximum', xy=(6.28, 1), xytext=(10, 4),arrowprops=dict(facecolor='black', shrink=0.05)) ax.annotate('local minimum', xy=(5 * np.pi, -1), xytext=(2, -6),arrowprops=dict(arrowstyle="->",connectionstyle="angle3,angleA=0,angleB=-90")); plt.show()
箭頭的風(fēng)格是通過 arrowprops 字典控制的,里面有許多可用的選項(xiàng)。由于這些選項(xiàng)在Matplotlib 的官方文檔中都有非常詳細(xì)的介紹,我就不再贅述,僅做一點(diǎn)兒功能演示。
帶注釋的日均出生人數(shù)
讓我們用前面的美國出生人數(shù)圖來演示一些箭頭注釋
fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax) # 在圖上增加箭頭標(biāo)簽 ax.annotate("New Year's Day", xy=('2012-1-1', 4100), xycoords='data',xytext=(50, -30), textcoords='offset points',arrowprops=dict(arrowstyle="->",connectionstyle="arc3,rad=-0.2")) ax.annotate("Independence Day", xy=('2012-7-4', 4250),xycoords='data',bbox=dict(boxstyle="round", fc="none", ec="gray"),xytext=(10, -40), textcoords='offset points', ha='center', arrowprops=dict(arrowstyle="->")) ax.annotate('Labor Day', xy=('2012-9-4', 4850), xycoords='data', ha='center', xytext=(0, -20), textcoords='offset points') ax.annotate('', xy=('2012-9-1', 4850), xytext=('2012-9-7', 4850), xycoords='data', textcoords='data', arrowprops={'arrowstyle': '|-|,widthA=0.2,widthB=0.2', }) ax.annotate('Halloween', xy=('2012-10-31', 4600), xycoords='data', xytext=(-80, -40), textcoords='offset points', arrowprops=dict(arrowstyle="fancy", fc="0.6", ec="none", connectionstyle="angle3,angleA=0,angleB=-90")) ax.annotate('Thanksgiving', xy=('2012-11-25', 4500), xycoords='data', xytext=(-120, -60), textcoords='offset points', bbox=dict(boxstyle="round4,pad=.5", fc="0.9"), arrowprops=dict(arrowstyle="->", connectionstyle="angle,angleA=0,angleB=80,rad=20")) ax.annotate('Christmas', xy=('2012-12-25', 3850), xycoords='data', xytext=(-30, 0), textcoords='offset points', size=13, ha='right', va="center", bbox=dict(boxstyle="round", alpha=0.1), arrowprops=dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1)); # 設(shè)置坐標(biāo)軸標(biāo)題 ax.set(title='USA births by day of year (1969-1988)', ylabel='average daily births') # 設(shè)置x軸刻度值,讓月份居中顯示 ax.xaxis.set_major_locator(mpl.dates.MonthLocator()) ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15)) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h')); ax.set_ylim(3600, 5400);
import matplotlib.pyplot as plt import matplotlib as mpl plt.style.use('seaborn-whitegrid') import numpy as np import pandas as pd births = pd.read_csv('C:\\Users\\Y\\Desktop\\data-CDCbirths-master\\births.csv') quartiles = np.percentile(births['births'], [25, 50, 75]) mu, sig = quartiles[1], 0.74 * (quartiles[2] - quartiles[0]) births = births.query('(births > @mu - 5 * @sig) & (births < @mu + 5 * @sig)') births['day'] = births['day'].astype(int) births.index = pd.to_datetime(10000 * births.year + 100 * births.month + births.day, format='%Y%m%d') births_by_date = births.pivot_table('births', [births.index.month, births.index.day]) births_by_date.index = [pd.datetime(2012, month, day) for (month, day) in births_by_date.index] fig, ax = plt.subplots(figsize=(12, 4)) births_by_date.plot(ax=ax) # 在圖上增加箭頭標(biāo)簽 ax.annotate("New Year's Day", xy=('2012-1-1', 4100), xycoords='data', xytext=(50, -30), textcoords='offset points', arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=-0.2")) ax.annotate("Independence Day", xy=('2012-7-4', 4250), xycoords='data', bbox=dict(boxstyle="round", fc="none", ec="gray"), xytext=(10, -40), textcoords='offset points', ha='center', arrowprops=dict(arrowstyle="->")) ax.annotate('Labor Day', xy=('2012-9-4', 4850), xycoords='data', ha='center', xytext=(0, -20), textcoords='offset points') ax.annotate('', xy=('2012-9-1', 4850), xytext=('2012-9-7', 4850), xycoords='data', textcoords='data', arrowprops={'arrowstyle': '|-|,widthA=0.2,widthB=0.2', }) ax.annotate('Halloween', xy=('2012-10-31', 4600), xycoords='data', xytext=(-80, -40), textcoords='offset points', arrowprops=dict(arrowstyle="fancy", fc="0.6", ec="none", connectionstyle="angle3,angleA=0,angleB=-90")) ax.annotate('Thanksgiving', xy=('2012-11-25', 4500), xycoords='data', xytext=(-120, -60), textcoords='offset points', bbox=dict(boxstyle="round4,pad=.5", fc="0.9"), arrowprops=dict(arrowstyle="->", connectionstyle="angle,angleA=0,angleB=80,rad=20")) ax.annotate('Christmas', xy=('2012-12-25', 3850), xycoords='data',xytext=(-30, 0), textcoords='offset points',size=13, ha='right', va="center",bbox=dict(boxstyle="round", alpha=0.1),arrowprops=dict(arrowstyle="wedge,tail_width=0.5", alpha=0.1)); # 設(shè)置坐標(biāo)軸標(biāo)題 ax.set(title='USA births by day of year (1969-1988)',ylabel='average daily births') # 設(shè)置x軸刻度值,讓月份居中顯示 ax.xaxis.set_major_locator(mpl.dates.MonthLocator()) ax.xaxis.set_minor_locator(mpl.dates.MonthLocator(bymonthday=15)) ax.xaxis.set_major_formatter(plt.NullFormatter()) ax.xaxis.set_minor_formatter(mpl.dates.DateFormatter('%h')); ax.set_ylim(3600, 5400); plt.show()
你可能已經(jīng)注意到了,箭頭和文本框的配置功能非常細(xì)致,這樣你就可以創(chuàng)建自己想要的箭頭風(fēng)格了。不過,功能太過細(xì)致往往也就意味著操作起來比較復(fù)雜,如果真要做一個產(chǎn)品級的圖形,可能得耗費(fèi)大量的時間。最后我想說一句,前面適用的混合風(fēng)格并不是數(shù)據(jù)可視化的最佳實(shí)踐,僅僅是為演示一些功能而已。
到此這篇關(guān)于Python之Matplotlib文字與注釋的使用方法的文章就介紹到這了,更多相關(guān)Matplotlib文字與注釋內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python使用Tkinter?GUI實(shí)現(xiàn)輸入驗(yàn)證功能
這篇文章主要介紹了Python中使用Tkinter?GUI實(shí)現(xiàn)輸入驗(yàn)證,文中通過一個完整示例代碼給大家介紹Python?Tkinter?GUI輸入驗(yàn)證功能,需要的朋友可以參考下2022-04-04解決pytorch?model代碼內(nèi)tensor?device不一致的問題
這篇文章主要介紹了pytorch?model代碼內(nèi)tensor?device不一致的問題,本文給大家分享完美解決方案,對pytorch?tensor?device不一致問題解決方案感興趣的朋友跟隨小編一起看看吧2023-07-07python接口調(diào)用已訓(xùn)練好的caffe模型測試分類方法
今天小編就為大家分享一篇python接口調(diào)用已訓(xùn)練好的caffe模型測試分類方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08教你怎么用Python selenium操作瀏覽器對象的基礎(chǔ)API
今天給大家?guī)淼氖顷P(guān)于Python的相關(guān)知識,文章圍繞著怎么用Python selenium操作瀏覽器對象的基礎(chǔ)API展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06詳解Python網(wǎng)絡(luò)框架Django和Scrapy安裝指南
這篇文章主要介紹了詳解Python網(wǎng)絡(luò)框架Django和Scrapy安裝指南,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-04-04caffe的python接口之手寫數(shù)字識別mnist實(shí)例
這篇文章主要為大家介紹了caffe的python接口之手寫數(shù)字識別mnist實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06python進(jìn)行TCP端口掃描的實(shí)現(xiàn)
這篇文章主要介紹了python進(jìn)行TCP端口掃描的實(shí)現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12PyCharm配置KBEngine快速處理代碼提示沖突、配置命令問題
這篇文章主要介紹了PyCharm配置KBEngine,解決代碼提示沖突、配置命令,本文通過圖文并茂的形式給大家介紹的超詳細(xì),需要的朋友可以參考下2021-04-04