在 Bokeh 中建立互動式視覺化應用程式
有時我會利用資料科學來解決特定問題。其他時候,我會嘗試一種新工具,比如說 Bokeh ,因為我在 Twitter 上看到一些很酷的專案,就會想:“那看起來很棒。雖然我不確定什麼時候會用到,但遲早會有用的。”幾乎每次我都這麼說,但是我最終都會找到這個工具的用途。 資料科學需要你掌握許多不同方面的知識,你永遠不會知道下一個你將使用的想法將來自哪裡!
作為一名資料科學研究人員,在試用了幾個星期之後,我終於在 Bokeh 的例子中找到了一個完美的用例。我的研究專案 涉及利用資料科學提高商業建築的能源效率。在最近的一次會議上,我們需要用一種方法來展示我們使用的眾多技術的成果。通常情況下都建議使用 powerpoint 來完成這項任務,但是效果並不明顯。大多數在會議中的人在看到第三張幻燈片時,就已經失去耐心了。儘管我對 Bokeh 還不是很熟悉,但我仍然自願嘗試利用這個庫做一個互動式應用程式,我認為這會擴充套件我的技能,創造一個吸引人的方式來展示我們的專案。安全起見,我們團隊準備了一個演示的備份,但在我向他們展示了一部分初稿之後,他們便給予了全部支援。最終的互動式儀表板在會議中脫穎而出,未來我們的團隊也將會使用:
為我的研究構建的 Bokeh 儀表盤的例子
雖然說並不是每一個你在 Twitter上看到的想法都可能對你的職業生涯產生幫助,但我可以負責的說,瞭解更多的資料科學技術不會有什麼壞處。 沿著這些思路,我開始了本系列文章,以展示 Bokeh 的功能, Bokeh 是 Python 中一個強大的繪相簿,他可以讓你製作互動式繪圖和儀表盤。儘管我不能向你展示有關我研究的儀表盤,但是我可以使用一個公開的資料集展示在 Bokeh 中構建視覺化的基礎知識。第三篇文章是我的 Bokeh 系列文章的延續,第一部分著重於構建一個簡單的圖 ,第二部分展示如何向 Bokeh 圖中新增互動。在這篇文章中,我們將看到如何設定一個完整的 Bokeh應用程式,並在您的瀏覽器中執行可訪問的本地Bokeh伺服器!
本文將重點介紹 Bokeh 應用程式的結構,而不是具體的細節,但是你可以在 GitHub 上找到所有內容的完整程式碼。我們將會使用 NYCFlights13 資料集,這是一個 2013 年從紐約 3 個機場起飛的航班的真實資訊資料集。這個資料集中有超過 300,000 個航班資訊,對於我們的儀表盤,我們將主要關注於到達延遲資訊的統計。
為了能完整執行整個應用程式,你需要先確保你已經安裝了 Bokeh(使用 pip install bokeh
),從 GitHub上 下載 [bokeh_app.zip](https://github.com/WillKoehrsen/Bokeh-Python-Visualization/blob/master/bokeh_app.zip)
資料夾, 解壓,並在當前目錄開啟一個命令視窗,並輸入 bokeh serve --show bokeh_app
。這會設定一個 Bokeh 的本地服務 同時還會在你的瀏覽器中開啟一個應用(當然你也可以使用 Bokeh 的線上服務,但是目前對我們來說本地主機足矣)。
最終產品
在我們深入討論細節之前,讓我們先來看看我們的最終產品,這樣我們就可以看到各個部分是如何組合在一起的。下面是一個短片,展示了我們如何與完整的儀表盤互動:
- YouTube 視訊連結:youtu.be/VWi3HAlKOUQ
Bokeh 航班應用最終版
我在本地伺服器上執行的瀏覽器(在Chrome的全屏模式下)中使用 Bokeh 應用程式。在頂部我們看到許多選項卡,每個選項卡包含不同部分的應用程式。儀表盤的想法是,雖然每個選項卡可以獨立存在,但是我們可以將其中許多選項卡連線在一起,以支援對資料的完整探索。這段視訊展示了我們可以用 Bokeh 製作的圖表的範圍,從直方圖和密度圖,到可以按列排序的資料表,再到完全互動式的地圖。使用 Bokeh 這個庫除了可以建立豐富的圖形外,另一個好處是互動。每個標籤都有一個互動元素可以讓使用者參與到資料中,並自己探索。從經驗來看,當探索一個資料集時,人們喜歡自己去洞察,我們可以讓他們通過各種控制元件來選擇和過濾資料。
現在我們對目標儀表盤已經有一個概念了,接下來讓我們看看如何建立 Bokeh 應用程式。 我強烈建議你下載這些程式碼,以供參考!
Bokeh 應用的結構
在編寫任何程式碼之前,為我們的應用程式建立一個框架是很重要的。在任何專案中,很容易被編碼衝昏頭腦,很快就會迷失在一堆尚未完成的指令碼和錯位的資料檔案中,因此我們想要在編寫程式碼和插入資料前先建立一個框架。這個組織將幫助我們跟蹤應用程式中的所有元素,並在不可避免地出錯時幫助我們進行除錯。此外,我們可以在未來的專案中複用這個框架,這樣我們在規劃階段的初始投資將在未來得到回報。
為了設定一個 Boken 應用,我建立了一個名為bokeh_app
的根目錄來儲存所有內容。 在這個目錄中,我們建立了一個子目錄用來存檔資料(命名為 data
),另一個子目錄用來存放指令碼檔案(命名為 script
)並通過一個 main.py
檔案將所有的東西組合在一起.。通常,為了管理所有程式碼,我發現最好將每個選項卡的程式碼儲存在單獨的 Python 指令碼中,並從單個主指令碼呼叫它們。下面是我為 Bokeh 應用程式所建立的檔案結構,它改編自官方文件。
bokeh_app
|
+--- data
| +--- info.csv
| +--- info2.csv
|
+--- scripts
| +--- plot.py
| +--- plot2.py
|
+--- main.py
複製程式碼
對於 flight 應用程式,其結構大致如下:
航班儀表盤的資料夾結構
在 bokeh_app
目錄下有三個主要部分: data
, scripts
, 和 main.py
。當需要執行伺服器時,我們在 bokeh_app
目錄執行 Bokeh ,它會自動搜尋並執行 main.py
指令碼。有了總體結構之後,讓我們來看看 main.py
檔案,我把它稱為 Bokeh 應用程式的啟動程式(並不是專業術語)!
main.py
main.py
指令碼是 Bokeh 應用程式的啟動指令碼。它載入資料,並把傳遞給其他指令碼,獲取結果圖,並將它們組織好後單個顯示出來。這將是我展示的唯一一個完整的指令碼,因為它對應用程式非常重要:
# Pandas for data management
import pandas as pd
# os methods for manipulating paths
from os.path import dirname, join
# Bokeh basics
from bokeh.io import curdoc
from bokeh.models.widgets import Tabs
# Each tab is drawn by one script
from scripts.histogram import histogram_tab
from scripts.density import density_tab
from scripts.table import table_tab
from scripts.draw_map import map_tab
from scripts.routes import route_tab
# Using included state data from Bokeh for map
from bokeh.sampledata.us_states import data as states
# Read data into dataframes
flights = pd.read_csv(join(dirname(__file__), 'data', 'flights.csv'),
index_col=0).dropna()
# Formatted Flight Delay Data for map
map_data = pd.read_csv(join(dirname(__file__), 'data', 'flights_map.csv'),
header=[0,1], index_col=0)
# Create each of the tabs
tab1 = histogram_tab(flights)
tab2 = density_tab(flights)
tab3 = table_tab(flights)
tab4 = map_tab(map_data, states)
tab5 = route_tb(flights)
# Put all the tabs into one application
tabs = Tabs(tabs = [tab1, tab2, tab3, tab4, tab5])
# Put the tabs in the current document for display
curdoc().add_root(tabs)
複製程式碼
我們從必要的導包開始,包括建立選項卡的函式,每個選項卡都儲存在 scripts
目錄中的單獨指令碼中。如果你看下檔案結構,注意這裡有一個 __init__.py
檔案在 scripts
目錄中。這是一個完全空白的檔案,需要放在目錄中,以允許我們使用相對語句匯入適當的函式 (例如 from scripts.histogram import histogram_tab
).我不太清楚為什麼需要這樣做,但它確實有效(我曾經解決過這個問題,這裡是 Stack Overflow的答案).
在匯入庫和指令碼後,我們利用 Python [__file__](https://stackoverflow.com/questions/9271464/what-does-the-file-variable-mean-do/9271617)
屬性讀取必要的資料。在本例中,我們使用了兩個 pandas 資料框(flights
和 map_data
)以及包含在 Bokeh 中的美國各州的資料。讀取資料之後,指令碼繼續進行執行:它將適當的資料傳遞給每個函式,每個函式繪製並返回一個選項卡,主指令碼將所有這些選項卡組織在一個稱為 tabs
的佈局中。作為這些獨立選項卡函式的示例,讓我們來看看繪製 map_tab
的函式。
該函式接收 map_data
(航班資料的格式化版本)和美國各州資料,併為選定的航空公司生成航線圖:
地圖選項卡
我們在本系列的第 2 部分中介紹了互動式情節,而這個情節只是該思想的一個實現。功能整體結構為:
def map_tab(map_data, states):
...
def make_dataset(airline_list):
...
return new_src
def make_plot(src):
...
return p
def update(attr, old, new):
...
new_src = make_dataset(airline_list)
src.data.update(new_src.data)
controls = ...
tab = Panel(child = layout, title = 'Flight Map')
return tab
複製程式碼
我們看到了熟悉的 make_dataset
, make_plot
, 和 update
函式,這些函式用於[使用互動式控制元件繪製繪圖](towardsdatascience.com/data- visualiz-with - bokehin - pythonpart -ii-interactions-a4cf994e2512)。一旦我們設定好了圖,最後一行將整個圖返回給主指令碼。每個單獨的指令碼(5個選項卡對應5個選項卡)都遵循相同的模式。
回到主指令碼,最後一步是收集選項卡並將它們新增到一個單獨的文件中。
# Put all the tabs into one application
tabs = Tabs(tabs = [tab1, tab2, tab3, tab4, tab5])
# Put the tabs in the current document for display
curdoc().add_root(tabs)
複製程式碼
選項卡顯示在應用程式的頂部,就像任何瀏覽器中的選項卡一樣,我們可以輕鬆地在它們之間切換以檢視資料。
執行 Bokeh 服務
在完成所有的設定和編碼之後,在本地執行 Bokeh 伺服器非常簡單。我們開啟一個命令列介面(我更喜歡 Git Bash,但任何一個都可以),切換到包含 bokeh_app
的目錄,並執行 bokeh serve --show bokeh_app
。假設所有程式碼都正確,應用程式將自動在瀏覽器中開啟地址 http://localhost:5006/bokeh_app
。然後,我們就可以訪問應用程式並檢視我們的儀表盤了!
Bokeh 航班應用最終版
在 Jupyter Notebook 中除錯
如果出了什麼問題(在我們剛開始編寫儀表盤的時候,肯定會出現這種情況),令人沮喪的是,我們必須停止伺服器、對檔案進行更改並重新啟動伺服器,以檢視我們的更改是否達到了預期的效果。為了快速迭代和解決問題,我通常在 Jupyter Notebook 中開發圖。Jupyter Notebook 對 Bokeh 來說是一個很好的開發環境,因為你可以在筆記本中建立和測試完全互動式的繪圖。語法略有不同,但一旦你有了一個完整的圖,程式碼只需稍加修改,就可以複製貼上到一個獨立的 .py
指令碼。要了解這一點的實際應用,請檢視 [Jupyter Notebook](github.com/willkoehrse… - pyth-visualization/blob/master/application/app_development .ipynb)。
總結
一個完全可互動式的 Bokeh 儀表盤可以使任何資料科學專案脫穎而出。我經常看到我的同事們做了很多非常棒的統計工作,但卻不能清楚地表達其結果,這意味著所有這些工作都沒有得到應有的認可。從個人經驗來看,我認為 Bokeh 應用程式在交流結果方面非常麼有效。雖然製作一個完整的儀表板需要做很多工作(超過600行程式碼),但其結果是值得的。此外,一旦我們有了一個應用程式,我們就可以使用 GitHub 快速地共享它,如果我們對我們的結構很瞭解,我們就可以在其他專案中重用這個框架。
從這個專案中得出的關鍵點適用於許多常規資料科學專案:
- 在開始一項資料科學任務之前,擁有適當的框架/結構( Bokeh 或其他的框架)是至關重要的。這樣,您就不會發現自己迷失在試圖查詢錯誤的程式碼森林中。而且,一旦我們開發了一個有效的框架,它就可以以最小的工作量被複用,從而在未來帶來收益。
- 找到一個除錯周期,使你能夠快速進行想法迭代是至關重要的。 Jupyter Notebook 支援編寫程式碼—檢視結果—修復錯誤的迴圈,這有助於提高開發週期的效率(至少對於小型專案來說是這樣)。
- Bokeh 中的互動式應用程式將提升您的專案並鼓勵使用者參與。儀表盤可以是獨立的探索性專案,也可以突出顯示你已經完成的所有艱難的分析工作!
- 你永遠不知道在哪裡可以找到下一個你在工作中能用到的或有幫助的工具。所以睜大你的眼睛,不要害怕嘗試新的軟體和技術!
這就是本文和本系列的全部內容,儘管我計劃在未來在額外發布有關 Bokeh 的獨立教程。以一種令人信服的方式展示資料科學成果是至關重要的,有了像 Bokeh 和 plot.ly 這樣的庫,製作互動式圖形變得越來越容易。你可以在 Bokeh GitHub repo 檢視我所有的工作,免費 fork 它並開始你自己的專案。現在,我渴望看到其他人能創造出什麼!
一如既往地,我歡迎反饋和建設性的批評。你可以通過Twitter @koehrsen_will聯絡到我。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。