數(shù)據(jù)科學(xué) IPython 筆記本 8.12 文本和注解

8.12 文本和注解

原文:Text and Annotation

譯者:飛龍

協(xié)議:CC BY-NC-SA 4.0

本節(jié)是《Python 數(shù)據(jù)科學(xué)手冊》(Python Data Science Handbook)的摘錄。

創(chuàng)建良好的可視化涉及引導(dǎo)讀者并使圖形講述故事。在某些情況下人柿,可以以完全可視的方式講述這個故事柴墩,而不需要添加文本,但在其他情況下凫岖,需要小的文本提示和標(biāo)簽江咳。也許你將使用的最基本的注釋類型是軸標(biāo)簽和標(biāo)題,但選項超出了這個范圍哥放。讓我們看看一些數(shù)據(jù)歼指,以及我們?nèi)绾慰梢暬妥⑨屗瑏碛兄趥鬟_(dá)有趣的信息甥雕。 我們首先設(shè)置筆記本來繪圖并導(dǎo)入我們將使用的函數(shù):

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib as mpl
plt.style.use('seaborn-whitegrid')
import numpy as np
import pandas as pd

示例: 美國新生兒的假期效應(yīng)

讓我們回到之前處理的一些數(shù)據(jù)踩身,在“示例:出生率數(shù)據(jù)”中,我們在日歷年上生成了平均出生率的圖表社露;如前所述挟阻,這些數(shù)據(jù)可以在 https://raw.githubusercontent.com/jakevdp/data-CDCbirths/master/births.csv 下載。

我們將使用我們在那里使用的相同清理過程開始峭弟,并繪制結(jié)果:

births = pd.read_csv('data/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);
png

When we're communicating data like this, it is often useful to annotate certain features of the plot to draw the reader's attention.
This can be done manually with the plt.text/ax.text command, which will place text at a particular x/y value:

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)

# 標(biāo)記軸域
ax.set(title='USA births by day of year (1969-1988)',
       ylabel='average daily births')

# 使用中心化的月標(biāo)簽將 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'));
png

ax.text方法接受x位置附鸽,y位置,字符串瞒瘸,然后是可選關(guān)鍵字坷备,指定文本的顏色,大小情臭,樣式省撑,對齊方式和其他屬性。在這里俯在,我們使用ha='right'ha='center'竟秫,其中ha是 horizonal alignment 的縮寫□卫郑可用選項的更多信息肥败,請參閱plt.text()mpl.text.Text()的文檔字符串。

變換和文本位置

在前面的示例中劈猿,我們將文本注釋錨定到數(shù)據(jù)位置。 有時最好將文本錨定到軸或圖上的位置潮孽,與數(shù)據(jù)無關(guān)揪荣。在 Matplotlib 中,這是通過修改變換來完成的往史。

任何圖形顯示框架都需要一些在坐標(biāo)系之間進(jìn)行轉(zhuǎn)換的方案仗颈。例如,(x, y) = (1, 1)處的數(shù)據(jù)點,需要以某種方式表示在圖上的某個位置挨决,而該位置又需要在屏幕上以像素表示请祖。在數(shù)學(xué)上,這種坐標(biāo)轉(zhuǎn)換相對簡單脖祈,Matplotlib 有一套完善的工具肆捕,它們在內(nèi)部使用來執(zhí)行(這些工具可以在matplotlib.transforms子模塊中進(jìn)行探索)。

普通用戶很少需要關(guān)心這些變換的細(xì)節(jié)盖高,但在考慮在圖形上放置文本時慎陵,它是有用的知識。 在這種情況下喻奥,有三種預(yù)定義的轉(zhuǎn)換可能很有用:

  • ax.transData:數(shù)據(jù)坐標(biāo)相關(guān)的變換
  • ax.transAxes:軸域(以軸域維度為單位)相關(guān)的變換
  • fig.transFigure:圖形(以圖形維度為單位)相關(guān)的變換

這里讓我們看一下席纽,使用這些變換在不同位置繪制文本的示例:

fig, ax = plt.subplots(facecolor='lightgray')
ax.axis([0, 10, 0, 10])

# transform=ax.transData 是默認(rèn)值,但是我們無論如何也要指定它
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);
png

請注意撞蚕,默認(rèn)情況下润梯,文本在指定坐標(biāo)的上方和左側(cè)對齊:這里,在每個字符串的開頭的'.'將近似標(biāo)記給定的坐標(biāo)位置甥厦。

transData坐標(biāo)給出了關(guān)聯(lián)x軸和y軸標(biāo)簽的常用數(shù)據(jù)坐標(biāo)纺铭。transAxes坐標(biāo)給出了相對于軸域左下角(這里是白框)的位置,作為軸域大小的比例矫渔。transFigure坐標(biāo)是相似的彤蔽,但是指定相對于圖左下角(這里是灰框)的位置,作為圖形大小的比例庙洼。

現(xiàn)在請注意顿痪,如果我們更改軸限制,那么只有transData坐標(biāo)會受到影響油够,而其他坐標(biāo)則保持不變:

ax.set_xlim(0, 2)
ax.set_ylim(-6, 6)
fig
png

通過交互式更改軸限制可以更清楚地看到這種行為:如果你在筆記本中執(zhí)行此代碼蚁袭,你可以通過將%matplotlib inline更改為%matplotlib notebook,并使用每個繪圖的菜單與它互動來實現(xiàn)它石咬。

箭頭和標(biāo)注

除了刻度線和文本揩悄,另一個有用的標(biāo)注或標(biāo)記是簡單的箭頭。

在 Matplotlib 中繪制箭頭通常比砍價要困難得多鬼悠。雖然plt.arrow()函數(shù)是可用的删性,我不建議使用它:它創(chuàng)建的箭頭是 SVG 對象,它們會受到不同長寬比的影響焕窝,結(jié)果很少是用戶所期望的蹬挺。相反,我建議使用plt.annotate()函數(shù)它掂。此函數(shù)可創(chuàng)建一些文本和箭頭呆瞻,并且箭頭可以非常靈活地指定。

在這里秀鞭,我們將使用annotate及其幾個選項:

%matplotlib inline

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"));
png

箭頭樣式通過arrowprops字典控制,該字典有許多選項垃沦。這些選項在 Matplotlib 的在線文檔中有相當(dāng)詳細(xì)的記錄,因此用押,比起在此復(fù)述這些選項肢簿,快速展示一些選項可能更有用。讓我們使用之前的出生率圖表演示幾種可用選項:

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));

# 標(biāo)記軸域
ax.set(title='USA births by day of year (1969-1988)',
       ylabel='average daily births')

# 使用中心化的月標(biāo)簽將 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);

[圖片上傳失敗...(image-6e934c-1547868405690)]

你會注意到箭頭和文本框的規(guī)格非常詳細(xì):這使你能夠創(chuàng)建幾乎任何箭頭樣式只恨。不幸的是译仗,這也意味著這些功能通常必須手動調(diào)整,這個過程在制作出版品質(zhì)的圖形時非常耗時官觅!最后我要提醒你纵菌,前面的樣式混合絕不是展示數(shù)據(jù)的最佳實踐,而是作為一些可用選項的演示休涤。

可用箭頭和注釋樣式的更多討論和示例咱圆,可以在 Matplotlib 庫中找到,特別是標(biāo)注的演示功氨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末序苏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捷凄,更是在濱河造成了極大的恐慌忱详,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件跺涤,死亡現(xiàn)場離奇詭異匈睁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)桶错,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進(jìn)店門航唆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人院刁,你說我怎么就攤上這事糯钙。” “怎么了退腥?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵任岸,是天一觀的道長。 經(jīng)常有香客問我狡刘,道長享潜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任颓帝,我火速辦了婚禮米碰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘购城。我一直安慰自己吕座,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布瘪板。 她就那樣靜靜地躺著吴趴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪侮攀。 梳的紋絲不亂的頭發(fā)上锣枝,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天,我揣著相機(jī)與錄音兰英,去河邊找鬼撇叁。 笑死,一個胖子當(dāng)著我的面吹牛畦贸,可吹牛的內(nèi)容都是我干的陨闹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼薄坏,長吁一口氣:“原來是場噩夢啊……” “哼趋厉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起胶坠,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤君账,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沈善,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乡数,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年矮瘟,在試婚紗的時候發(fā)現(xiàn)自己被綠了瞳脓。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡澈侠,死狀恐怖劫侧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哨啃,我是刑警寧澤烧栋,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站拳球,受9級特大地震影響审姓,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜祝峻,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一魔吐、第九天 我趴在偏房一處隱蔽的房頂上張望扎筒。 院中可真熱鬧,春花似錦酬姆、人聲如沸嗜桌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骨宠。三九已至,卻和暖如春相满,著一層夾襖步出監(jiān)牢的瞬間层亿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工立美, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留匿又,地道東北人。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓建蹄,卻偏偏與公主長得像琳省,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子躲撰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,515評論 2 359

推薦閱讀更多精彩內(nèi)容