[譯] 利用 Python 中的 Bokeh 實現數據可視化,第一部分:入門

提高你的可視化遊數據html

若是沒有有效的方法來傳達結果,那麼再複雜的統計分析也毫無心義。這一點我在最近的研究項目中深有體會,咱們使用數據科學來提升建築能效。在過去的幾個月裏,我團隊成員中的一我的一直在致力於研究一種叫作 wavelet transforms,用於分析時間序列頻率成分的技術。該方法取得了積極的效果,但她在解釋過程當中遇到了困難,所幸的是,她沒有迷失在技術細節中。前端

她很憤怒,問我可否用視覺表達來講明這種變換。我使用了叫作 gganimate 的 R 包,在幾分鐘以內製做了一個簡單的動畫,展現了該方法是如何轉換時間序列的。如今,個人團隊成員能夠用這個讓人直觀地瞭解技術是如何工做的東西來取代費勁的語言描述。個人結論是,咱們能夠作最嚴格的分析,但在一天結束時,全部人都想看到的是一個 gif!雖說這話是開玩笑,但它蘊含着一個道理:不能清楚地表達結果,就會對結果產生影響,而數據可視化一般是展現分析結果的最佳方法。python

可用於數據科學的資源正在迅速增長,在可視化領域中尤其明顯,彷佛每週都有一種新的嘗試。隨着這些技術的進步,它們逐漸出現了一個共同的趨勢:增長交互性。人們喜歡在靜態圖中查看數據,但他們更喜歡的是使用數據,並利用這些數據來查看參數的變化對結果的影響。在個人研究中,有一份報告是用來告訴業主經過改變他們的空調使用時間能夠節省下多少度電,但若是給他們一個能夠交互的表,他們就能夠本身選擇不一樣的時間表,來觀察不用時間是如何影響用電的,這種方式更加有效。最近,受交互式繪圖趨勢的啓發,以及對不斷學習新工具的渴望,我一直在學習使用一個叫作 Bokeh 的 Python 庫。我爲個人研究項目構建的儀表盤中顯示了 Bokeh 交互功能的一個示例:android

儘管我沒法共享這個項目的整個代碼,但我能夠經過使用公開可用數據構建徹底交互的 Bokeh 應用程序的示例。本系列文章將介紹使用 Bokeh 建立應用程序的整個過程。對於第一篇文章,咱們將介紹 Bokeh 的基本元素,咱們將在之後的文章中對其進行構建,在本系列文章中,咱們將使用 nycflights13 數據集,該數據集有 2013 年以來超過 30 萬次航班的記錄。咱們首先將重點放在可視化單個變量上,在這種狀況下,航班的延遲到達以分鐘爲單位,咱們將從構造一個基本的柱狀圖開始,這是顯示一個連續變量的擴展和位置的經典方法。完整的代碼能夠在 GitHub 查看,第一個 Jupyter notebook 能夠在這裏看到。這篇文章關注的是視覺效果,因此我鼓勵任何人查看代碼,若是他們想看到無聊但又必不可少數據清洗和格式化的步驟!ios

Bokeh 基礎

Bokeh 的主要概念是一次創建一個圖層。咱們首先建立一個圖,而後向圖中添加名爲 glyphs 的元素。(對於那些使用 ggplot 的人來講,glyphs 的概念與地理符號的想法本質上是同樣的,他們一次添加到一個「圖層」中。)根據所需的用途,glyphs 能夠呈現多種形狀:圓形、線條、補丁、條形、弧形等。讓咱們用正方形和圓形制做一個基本的圖來講明 glyphs 的概念。首先,咱們使用 figure 方法繪製一個圖,而後經過調用適當的方法傳入數據,將咱們的 glyphs 添加到繪圖中。最後,咱們展現繪圖(我使用的是 Jupyter Notebook,若是你使用時調用的是 output_notebook,就會看到對應的繪圖)。git

# bokeh 基礎
from bokeh.plotting import figure
from bokeh.io import show, output_notebook

# 建立帶標籤的空白圖
p = figure(plot_width = 600, plot_height = 600, 
           title = 'Example Glyphs',
           x_axis_label = 'X', y_axis_label = 'Y')

# 示例數據
squares_x = [1, 3, 4, 5, 8]
squares_y = [8, 7, 3, 1, 10]
circles_x = [9, 12, 4, 3, 15]
circles_y = [8, 4, 11, 6, 10]

# 添加方形 glyph
p.square(squares_x, squares_y, size = 12, color = 'navy', alpha = 0.6)
# 添加圓形 glyph
p.circle(circles_x, circles_y, size = 12, color = 'red')

# 設置爲在筆記本中輸出情節
output_notebook()
# 顯示繪圖
show(p)
複製代碼

這就造成了下面略顯平淡的繪圖:github

儘管在任何繪製圖庫中,咱們均可以很容易地製做這個圖表,但咱們能夠免費獲取一些工具,其中包含位於右側的 Bokeh 繪圖,包括 panning,縮放和繪圖保存功能。這些工具是可配置的,當咱們想研究咱們的數據時,這些工具會派上用場。web

咱們如今開始展現咱們的航班延遲數據。在跳轉到圖形以前,咱們應該加載數據並對其進行簡短的檢查(粗體 爲輸出代碼):後端

# 將 CSV 中的數據讀入
flights = pd.read_csv('../data/flights.csv', index_col=0)

# 興趣欄的統計數據彙總
flights['arr_delay'].describe()

count    327346.000000
mean          6.895377
std          44.633292
min         -86.000000
25%         -17.000000
50%          -5.000000
75%          14.000000
max        1272.000000
複製代碼

摘要統計數據爲咱們做出決策提供了信息:咱們有 32七、346 次航班,最小延遲事件爲 -86 分鐘,最大延遲事件爲 1272 分鐘,使人震驚的 21 小時!75% 的分位數只有 14 分鐘,因此咱們能夠假設 1000 分鐘以上的數字多是異常值(這並不意味着它們是非法的,只是極端的)。我會集中討論 -60 到 120 分鐘的延遲柱狀圖。分佈式

柱狀圖是單個變量初始可視化的常見選擇,由於它顯示了分佈式數據。x 位置是將變量分組成成爲 bin 的間隔的值,每一個條形的高度表示每一個間隔數據點的計數(數目)。在咱們的例子中,x 位置將表明以分鐘爲單位的延遲到達,高度是對應的 bin 中的航班數。Bokeh 沒有內置的柱狀圖,但咱們可使用 quad glyph 來指定每一個條形的底部、上、下、和右邊距。

要建立條形圖的數據,咱們要使用 numpy[histogram](https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.histogram.html)function,它計算每一個指定 bin 數據點的數值。咱們使用 5 分鐘的長度做爲函數將計算航班數在每五分鐘所花費的時間延誤。在生成數據以後,咱們將其放入一個 pandas dataframe 來將全部的數據保存在一個對象中。這裏的代碼對於理解 Bokeh 並非很重要,但鑑於 Numpy 和 pandas 在數據科學中的流行度,因此它仍是有些用處的。

"""Bins will be five minutes in width, so the number of bins is (length of interval / 5). Limit delays to [-60, +120] minutes using the range."""

arr_hist, edges = np.histogram(flights['arr_delay'], 
                               bins = int(180/5), 
                               range = [-60, 120])

# 將信息放入 dataframe
delays = pd.DataFrame({'arr_delay': arr_hist, 
                       'left': edges[:-1], 
                       'right': edges[1:]})
複製代碼

咱們的數據看起來像這樣:

flights 列是從 leftright 的每一個延遲間隔內飛行次數的計數。在這裏,咱們能夠生成一個新的 Bokeh 圖,並添加一個指定適當參數的 quad glpyh:

# 建立空白繪圖
p = figure(plot_height = 600, plot_width = 600, 
           title = 'Histogram of Arrival Delays',
          x_axis_label = 'Delay (min)]', 
           y_axis_label = 'Number of Flights')

# 添加一個 quad glphy
p.quad(bottom=0, top=delays['flights'], 
       left=delays['left'], right=delays['right'], 
       fill_color='red', line_color='black')

# 顯示繪圖
show(p)
複製代碼

生成此圖的大部分工做都是在數據格式化過程當中進行的,這在數據科學中並不常見!從咱們的繪圖中能夠看出,延遲到達幾乎是正態分佈的,右側有一個輕微的正斜度或重尾巴

有更簡單的方法能夠在 Python 中建立柱狀圖,也可使用幾行 [matplotlib](https://en.wikipedia.org/wiki/Matplotlib) 來獲取相同的結果。可是,Bokeh 繪圖所帶來的的開發的好處在於,它能夠提供將數據交互輕鬆地添加到圖形中的工具和方法。

添加交互性

咱們將在本系列中討論的第一類交互是被動交互。這些是擁護能夠採起的不改變顯示數據的操做。它們被稱爲 inspectors,由於他們容許用戶查看更詳細的「調查」數據。有用的 inspector 是當用戶鼠標在數據點上移動並調用 Bokeh 中的懸停工具時,會出現工具提示。

基礎的懸停工具提示

爲了添加工具提示,咱們須要將數據源從 dataframe 中更改成來自 ColumnDataSource,Bokeh 中的一個關鍵概念。這是一個專門用於繪圖的對象,它包含數據以及方法和屬性。ColumnDataSource 容許咱們在圖中添加註解和交互,也能夠從 pandas dataframe 中進行構建。真實數據被保存在字典中,能夠經過 ColumnDataSource 的 data 屬性訪問。這裏,咱們從數據源進行建立源,並查看數據字典中與 dataframe 列對應的鍵。

# 導入 ColumnDataSource 類
from bokeh.models import ColumnDataSource

# 將 dataframe 轉換爲 列數據源
src = ColumnDataSource(delays)
src.data.keys()

dict_keys(['flights', 'left', 'right', 'index'])
複製代碼

咱們使用 CloumDataSource 添加 glyphs 時,咱們將 CloumnDataSource 做爲 source 參數傳入,並使用字符串引用列名:

# 此次添加一個帶有源的 quad glyph
p.quad(source = src, bottom=0, top='flights', 
       left='left', right='right', 
       fill_color='red', line_color='black')
複製代碼

請注意,代碼如何引用特定的數據列,好比 ‘flights’、‘left’ 和 ‘right’,而不是像之前那樣使用 df['column'] 格式。

Bokeh 中的 HoverTool

一開始,HoverTool 的語法看上去會有些複雜,但通過實踐後,就會發現它們很容易建立。咱們將 HoverTool 實例做爲 tooltips 做爲 Python 元組傳遞給它,其中第一個元素是數據的標籤,第二個元素引出咱們要高亮顯示的特定數據。咱們可使用 ‘$’ 引用圖中任何屬性,例如 x 或 y 的位置,也可使用 ‘@’ 引用源中特定字段。這聽起來可能有點使人困惑,因此這裏有一個 HoverTool 的例子,咱們在這兩方面均可以這麼作:

# 使用 @ 引用咱們本身的數據字段
# 使用 $ 在圖上的位置懸停工具
h = HoverTool(tooltips = [('Delay Interval Left ', '@left'),
                          ('(x,y)', '($x, $y)')])
複製代碼

這裏,咱們使用 ‘@’ 引用 ColumnDataSource(它對應於原始 dataframe 的 ‘left’ 列)中的 left 數據字段,並使用 ‘$’ 引用光標的 (x,y) 位置。結果以下:

顯示不一樣數據引用的懸停工具提示

(x,y) 位置上是鼠標的位置,對咱們的柱狀圖沒有太大的幫助,由於咱們要找到給定條形中對應於條形頂部的飛行術。爲了修復這個問題,咱們將要修改咱們的工具提示實例來引用正確的列。格式化工具提示中的數據顯示可能會讓人沮喪,所以我一般在 dataframe 中使用正確的格式建立另外一列。例如,若是我但願個人工具提示顯示給定條的整個隔間,我會在數據框中建立一個格式化列:

# 添加一個列,顯示每一個間隔的範圍
delays['f_interval'] = ['%d to %d minutes' % (left, right) for left, right in zip(delays['left'], delays['right'])]
複製代碼

而後,我將 dataframe 轉換爲 CloumnDataSource,並在 HoverTool 調用中訪問該列。下面的代碼使用引用兩個格式化列的懸停工具建立繪圖,把那個將該工具添加到繪圖中。

# 建立一個空白繪圖
p = figure(plot_height = 600, plot_width = 600, 
           title = 'Histogram of Arrival Delays',
          x_axis_label = 'Delay (min)]', 
           y_axis_label = 'Number of Flights')

# 此次,添加帶有源的 quad glyph
p.quad(bottom=0, top='flights', left='left', right='right', source=src,
       fill_color='red', line_color='black', fill_alpha = 0.75,
       hover_fill_alpha = 1.0, hover_fill_color = 'navy')

# 添加引用格式化列的懸停工具
hover = HoverTool(tooltips = [('Delay', '@f_interval'),
                             ('Num of Flights', '@f_flights')])

# 繪圖樣式
p = style(p)

# 將懸停工具添加到圖中
p.add_tools(hover)

# 顯示繪圖
show(p)
複製代碼

在 Bokeh 樣式中,咱們以添加元素至原始的圖中來將元素添加到表中。請注意,在 p.quad glyph 調用中,有幾個額外的參數 hover_fill_alphahover_fill_color,當咱們的鼠標移動到條圖形時,這些參數會改變 glyph 的樣式。我還添加了 style 函數(可在筆記中查看相關代碼)。審美過程很無聊,因此一般我會寫一個應用於任何繪圖的函數。當我使用樣式時,我會保持簡單並專一於標籤的可讀性。繪圖的主要目的是顯示數據,添加沒必要要的元素只會下降繪圖的可用性!最後的繪圖以下所示:

當咱們的鼠標滑過不一樣的詞條時,會獲得該詞條精確的統計數據,它表示間隔以及在該間隔內飛行的次數。若是對繪圖比較滿意,能夠將其保存到 html 文件中進行共享:

# 導入保存函數
from bokeh.io import output_file

# 指定輸出文件並保存
output_file('hist.html')
show(p)
複製代碼

展望與總結

爲了獲取 Bokeh 的工做流程,我製做了不少次繪圖,因此若是這看起來有不少東西要學的時候,不要擔憂。在本系列教程中,咱們將獲得更多的練習!雖然Bokeh 看起來彷佛有不少工做要作,可是當咱們想要將咱們的視覺效果擴展到簡單的靜態圖像以外的時候,它的好處就不言而喻了。一旦咱們有了基本的圖,咱們就能夠經過增長更多的元素來提升視覺效果。例如,若是咱們想查看航空公司的延遲到達,咱們能夠製做一個交互式圖,讓用戶選擇和比較航空公司。咱們將把主動交互(那些更改顯示數據的交互)留到下一篇文章中,但下面是咱們目前能夠作的事情:

主動交互須要編寫更多的腳本,但這給了咱們可使用 Python 的機會!(若是有人想在下一篇文章以前看一下繪圖的代碼能夠在這裏進行查看。)

在本系列文章中,我想強調的是,Boken 或者任何一個庫工具永遠都不會是知足全部繪圖需求的一站式解決工具。Bokeh 容許用戶研究繪圖,但對於其餘應用,像簡單的探索性數據分析matplotlib 這樣的輕量級庫可能會更高效。本系列旨在爲你提供繪圖工具的另外一種選擇,這須要更加需求來進行抉擇。你知道的庫越多,就越能高效地使用可視化工具完成任務。

我一直以來都很是歡迎那些具備建設性的批評和反饋。大家能夠在 Twitter @koehrsen_will 上聯繫到我。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索