python數(shù)據(jù)可視化 – 利用Bokeh和Bottle.py在網(wǎng)頁上展示你的數(shù)據(jù)
在數(shù)據(jù)科學(xué)中,通過圖表將數(shù)據(jù)可視化是一個很重要的工作,在開始數(shù)據(jù)分析之前,通過數(shù)據(jù)可視化可以幫助我們理解數(shù)據(jù),而更重要的是,在完成分析、預(yù)測等等過程之后,我們需要通過數(shù)據(jù)可視化講結(jié)論展示出來。通過網(wǎng)頁創(chuàng)建可以交互的圖表是展示數(shù)據(jù)的一個重要手段。
1. 文章重點和項目介紹
本文的重點將是展示如何將bokeh和bottle集成在一起,并部署到服務(wù)器上,供他人訪問查閱,因此不會在bokeh和bottle,以及pandas的相關(guān)代碼具體實現(xiàn)細(xì)節(jié)上面面俱到,但是對于我們實現(xiàn)的代碼,還是會進(jìn)行講解(可能不會那么深入)。本文將選取中國2017到2019年的AQI數(shù)據(jù)作為項目的數(shù)據(jù)集,然后利用這些數(shù)據(jù)繪制3張表格(一張折線圖和兩張帶分組的柱狀圖),然后通過bottle和bootstrap前端模板建立一個展示網(wǎng)頁,最后會將這個網(wǎng)頁應(yīng)用部署到Heroku上邊(這一步作為參考,你可以通過localhost訪問本機(jī)服務(wù),或者選取其他云服務(wù)商的服務(wù)器)。
本文使用的數(shù)據(jù)集和代碼實現(xiàn)都可以在下邊這個github倉庫中找到:
https://github.com/pythonlibrary/bokeh-bottlepy
我已經(jīng)將數(shù)據(jù)集進(jìn)行過清理,數(shù)據(jù)集中包含規(guī)整的從2017年到2019年的各個城市的日AQI平均值。
2. 數(shù)據(jù)集研究和圖表準(zhǔn)備
在本節(jié)中,和大多數(shù)數(shù)據(jù)分析項目一樣,我們將使用jupyter notebook作為我們的環(huán)境,因為這個工具能夠方便的實現(xiàn)代碼修改和及時的代碼結(jié)果展示。
首先完成最重要的事情,導(dǎo)入必要的python庫
import numpy as np import pandas as pd from bokeh.plotting import figure, show from bokeh.models import ColumnDataSource, HoverTool from bokeh.transform import dodge from bokeh.io import output_notebook
然后在notebook中運行,下邊代碼來初始化bokeh,bokeh可以將圖標(biāo)輸出成不同的格式文件,如html等,但是要在notebook中顯示,則需要在最開始的時候指明。
output_notebook()
成功執(zhí)行完以后,notebook會提示成功加載bokeh環(huán)境,如下:
2.1 導(dǎo)入數(shù)據(jù)集
我們使用pandas的read_csv方法讀入數(shù)據(jù)集,并將一些城市的數(shù)據(jù)拿出來,因為讀入以后date一列的數(shù)據(jù)格式不是pandas datatime,我們在這里做一個轉(zhuǎn)換,方便后邊繪圖使用,因為數(shù)據(jù)集中還有一些其他空氣質(zhì)量指標(biāo)例如PM2.5等,我們僅僅選取AQI作為關(guān)注重點形成新的數(shù)據(jù)幀 df
cities = ['上海', '北京', '杭州', '寧波', '保定', '南京', '蘇州', '深圳', '廈門', '廣州'] df = pd.read_csv('AQI_merged.csv') df['date'] = pd.to_datetime(df['date']) df = df.sort_values(by='date').reset_index(drop=True) df = df[df['type']=='AQI']
我們的基礎(chǔ)數(shù)據(jù)幀(Dataframe)創(chuàng)建好以后,讓我們來看一下它里邊包含了什么數(shù)據(jù),我們使用如下代碼提取2019年的數(shù)據(jù),并且在notebook中展示前5條記錄。
df_2019_day = df[df['date']>='2019-01-01'] df_2019_day.head()
可以看出,在數(shù)據(jù)幀中,按照每一天為行,記錄了當(dāng)天幾個城市的AQI值。
2.2 繪制圖表
利用導(dǎo)入的數(shù)據(jù),我們將繪制3張圖表:
2019年上海,北京,深圳三地的每天AQI變化曲線(曲線圖)
2019年上海,北京,深圳三地的每月平均AQI對比(柱狀圖)
2017年到2019年北京每月平均AQI對比(柱狀圖)
圖表1:2019年上海,北京,深圳三地的每天AQI變化曲線
利用剛剛我們創(chuàng)建的df_2019_day數(shù)據(jù)幀,使用如下代碼繪制圖表,注意,我們使用了Bokeh提供的ColumnDataSource的方式來給bokeh圖表傳遞數(shù)據(jù)。
簡單說明一下:我們先使用figure創(chuàng)建了一個空的圖畫,然后用line方法畫了上海的數(shù)據(jù),然后重復(fù)line方法兩次在圖畫上添加了另外兩個城市的數(shù)據(jù),最后,通過add_tools方法添加了一個鼠標(biāo)懸停提示,用于顯示鼠標(biāo)位置的AQI值。
source = ColumnDataSource(df_2019_day) p = figure(x_axis_type="datetime", title="2019年AQI日均平均變化曲線", plot_width=900, plot_height=400) p.line('date', '上海', line_color='blue', legend_label='上海', source=source) p.line('date', '北京', line_color='green', legend_label='北京', source=source) p.line('date', '深圳', line_color='orange', legend_label='深圳', source=source) p.legend.location = "top_right" p.add_tools(HoverTool(tooltips=[("AQI", "$y")])) show(p)
圖表2:2019年上海,北京,深圳三地的每月平均AQI對比
我們想要畫出每月平均AQI,而數(shù)據(jù)幀中包含的是每日的AQI,因此,利用dataframe的groupby方法,可以求得每月的平均值。并新建了一列month來存放月信息。最后通過head方法查看下我們獲得的新的數(shù)據(jù)幀是否包含了按月平均的AQI信息。
pd.options.mode.chained_assignment = None df_2019_day['month'] = df_2019_day['date'].apply(lambda x: x.strftime('%Y-%m')) df_2019_month = df_2019_day.groupby(by='month').mean().reset_index() df_2019_month.head()
數(shù)據(jù)集處理結(jié)果符合我們的預(yù)期,接下來使用這個數(shù)據(jù)集繪制第二張圖表。因為我們想要比較不同城市同一個月的AQI,因此我們的柱狀圖需要分組顯示,這里使用了bokeh中的dodge方式,每一個dodge為一個城市的數(shù)據(jù),并指明了在圖表上的相對位置。
source = ColumnDataSource(df_2019_month) p = figure(x_range=list(df_2019_month['month']), title="2019年AQI", plot_width=900, plot_height=400) p.vbar(x=dodge('month', -0.25, range=p.x_range), top='上海', width=0.2, color="#c9d9d3", legend_label="上海", source=source) p.vbar(x=dodge('month', 0, range=p.x_range), top='北京', width=0.2, color="#718dbf", legend_label="北京", source=source) p.vbar(x=dodge('month', 0.25, range=p.x_range), top='深圳', width=0.2, color="#e84d60", legend_label="深圳", source=source) p.xgrid.grid_line_color = None p.y_range.start = 0 p.add_tools(HoverTool(tooltips=[("時間", "@month"), ("上海平均AQI", "@{上海}"), ("北京平均AQI", "@{北京}"), ("深圳平均AQI", "@{深圳}")])) show(p)
圖表3:2017年到2019年北京每月平均AQI對比
跟圖表2 類似我們對數(shù)據(jù)幀進(jìn)行必要的處理,同時因為我們要顯示不同的年月的對比,所以講年份和月份單獨放置到y(tǒng)ear和month列中。
df['date_ym'] = df['date'].apply(lambda x: x.strftime('%Y-%m')) df_month = df.groupby(by='date_ym').mean().reset_index() df_month['month'] = df_month['date_ym'].apply(lambda x: x.split('-')[-1]) df_month['year'] = df_month['date_ym'].apply(lambda x: x.split('-')[0]) df_month.head()
然后創(chuàng)建3個數(shù)據(jù)幀,每個僅包含一年的數(shù)據(jù)
df_2017 = df_month[df_month['year']=='2017'][['month', '北京']] df_2018 = df_month[df_month['year']=='2018'][['month', '北京']] df_2019 = df_month[df_month['year']=='2019'][['month', '北京']]
最后,還是通過相同的bokeh方法,繪制新的柱狀圖。
source_2017 = ColumnDataSource(df_2017) source_2018 = ColumnDataSource(df_2018) source_2019 = ColumnDataSource(df_2019) p = figure(x_range=list(df_2017['month']), title="2017-2019年北京AQI對比", plot_width=900, plot_height=400) p.vbar(x=dodge('month', -0.25, range=p.x_range), top='北京', width=0.2, color="#c9d9d3", legend_label="2017", source=source_2017) p.vbar(x=dodge('month', 0, range=p.x_range), top='北京', width=0.2, color="#718dbf", legend_label="2018", source=source_2018) p.vbar(x=dodge('month', 0.25, range=p.x_range), top='北京', width=0.2, color="#e84d60", legend_label="2019", source=source_2019) p.xgrid.grid_line_color = None p.y_range.start = 0 p.add_tools(HoverTool(tooltips=[("時間", "@month"), ("AQI", "@{北京}")])) show(p)
到這里我們的3張圖表已經(jīng)準(zhǔn)備好了,但是他們都是在notebook中運行的,后邊我們將對這些代碼進(jìn)行簡單的轉(zhuǎn)化,并嵌入到bottle網(wǎng)頁應(yīng)用中。
3. Bottle網(wǎng)頁應(yīng)用
bottle是一個超輕量級的python web框架,我們在本文中選擇了bottle而沒有選擇flask或者Django的原因就在于它的超輕量級,可以快速的搭建網(wǎng)頁應(yīng)用,對于以僅僅做數(shù)據(jù)展示為目的的網(wǎng)頁應(yīng)用,使用bottle可以讓你快速上手,讓你更專注于數(shù)據(jù)分析。
我們將采用bootstrap前端模板加bottle內(nèi)置的模板引擎的方式來實現(xiàn)這個應(yīng)用,為了快速實現(xiàn)這個目標(biāo),我們選取了https://github.com/arsho/bottle-bootstrap這個項目作為我們的初始代碼,所以,本文項目中使用到的網(wǎng)頁應(yīng)用代碼99%的實現(xiàn)來自于這個項目,我們僅僅做了一點改動。在本節(jié)內(nèi)容中,我們會講解一下bottle應(yīng)用的重點代碼和概念。
本文對應(yīng)的代碼可以在 https://github.com/pythonlibrary/bokeh-bottlepy 這個倉庫中找到。
3.1 文件夾結(jié)構(gòu)
我們的bokeh-bottlepy項目目錄結(jié)構(gòu)如下,其中
dataset文件夾:包含了數(shù)據(jù)集csv文件
static文件夾:包含了bootstrap前端框架代碼,包括css,JavaScript,以及fonts等,用于以bootstrap的主題來展現(xiàn)html頁面
views文件夾中:包含我們要如何展示數(shù)據(jù)的模板,本項目作為入門項目,其中僅僅包含了一個index.tpl文件,作為我們僅有的一個單頁面網(wǎng)頁的模板,該模板會由bottle應(yīng)用導(dǎo)入數(shù)據(jù)來渲染,最總形成用戶看到的頁面
app.py:為我們的入口文件,我們所有的python代碼將在這個里邊實現(xiàn),最終運行也是通過:python app.py來啟動服務(wù)
Procfile:涉及到Heroku部署,后邊我們會提到
3.2 路由
用python web框架實現(xiàn)的是動態(tài)的網(wǎng)頁,也就是說網(wǎng)頁是在用戶訪問的時候生成的,路由這個概念對于第一次接觸網(wǎng)頁應(yīng)用的人比較陌生,不過其實很簡單,通俗的講,用戶在點擊一個網(wǎng)頁上的鏈接或按鈕,或在瀏覽器地址欄中訪問一個鏈接的時候,網(wǎng)頁服務(wù)器端會根據(jù)鏈接的不同做不同的動作,并將結(jié)果組織成html并呈現(xiàn)給用戶,這一個過程就是路由。
在bottle中實現(xiàn)路由其實就是給每一個url實現(xiàn)一個對應(yīng)的處理方法。下邊的代碼就是本項目用到的所有相關(guān)的部分
dirname = '.' app = Bottle() debug(True) @app.route('/static/<filename:re:.*\.css>') def send_css(filename): return static_file(filename, root=dirname+'/static/asset/css') @app.route('/static/<filename:re:.*\.js>') def send_js(filename): return static_file(filename, root=dirname+'/static/asset/js') @app.route('/') def index(): data = { "developer_organization":"pythonlibrary.net"} return template('index', data = data)
所有bottle網(wǎng)頁應(yīng)用需要實例化一個Bottle對像,作為服務(wù)本身,這里我們起名叫app,同時打開了debug模式,即當(dāng)訪問url的時候,Bottle應(yīng)用會打印一些調(diào)試信息輔助開發(fā)人員定位問題。
路由函數(shù)的指定是通過@app.route裝飾器實現(xiàn)的,這個裝飾器的參數(shù)就是相對url,例如index函數(shù)的路由地址為/,如果本地服務(wù)端口為8080,則絕對url為:http://localhost:8080/,用戶在訪問這個地址的時候index函數(shù)將會被調(diào)用,而它的返回值就是用戶看到的頁面,這里是使用了template方法來使用data數(shù)據(jù)渲染模板,模板的概念我們下一章節(jié)會進(jìn)行介紹。
要做出一個漂亮的頁面,需要使用到復(fù)雜的JavaScript和css,所幸的是我們選擇的bootstrap框架為我們實現(xiàn)了這些復(fù)雜部分,我們只需要應(yīng)用它提供的模組就可以搭建出一個漂亮的網(wǎng)站。
在html中,JavaScript和css也是通過url來訪問到的,因此如果要使模板生效,需要告知bottle這些JavaScript和css需要從本地哪個路徑中去找,代碼中的send_css和send_js函數(shù)就是利用bottle 中的static_file函數(shù)來通知應(yīng)用本地的資源在什么位置,而上邊的路由地址則是用戶訪問網(wǎng)頁的時候再html中的地址,因此這兩個函數(shù)實現(xiàn)了,url和本地資源的連接。
3.3 模板實現(xiàn)
所有的Python網(wǎng)頁框架,在不使用前后端分離的方式開發(fā)網(wǎng)頁應(yīng)用的時候,都會包含一個模板的概念,這些框架大部分都繼承了自己的模板引擎,bottle中也集成了一個他們稱為SimpleTemplate的簡單模板引擎,當(dāng)然你可以選擇使用其他第三方的模板引擎,如nijia2,mako等。
所謂模板引擎其實即使基于模板關(guān)鍵字的替換,引擎提供了一系列的語法,引擎可以解析這些語法,做出相應(yīng)的動作,例如根據(jù)不同的情況填入不同的數(shù)據(jù),做循環(huán),判斷等等,然后其余的內(nèi)容將保持不變的放到輸出中,可以通過python的stringtemplate來類比。
我們這個項目中,index.tpl就是模板,里邊包含了SimpleTemplate可以識別的語法以及其他內(nèi)容,當(dāng)SimpleTemplate解析index.tpl總的語法,并填入合適的數(shù)據(jù),則最終會得到完整的html內(nèi)容,因此模板是 html + 引擎語法的集合,至于文件后綴tpl則無關(guān)緊要,可以使任何你定義的后綴,只是一般tpl代表template。
我們對原始代碼的該文件進(jìn)行一些修改:將head標(biāo)簽中的信息,按照我們的項目進(jìn)行修改
<meta name="description" content="Deploy Bokeh Data Visualization with Bottlepy"> <title>China AQI</title>
然后將導(dǎo)航條 navbar div按照我們的要求修改成我們自己的鏈接,將網(wǎng)頁主體container中最上邊的文字框改成我們的項目描述。
<div id="navbar" class="navbar-collapse collapse"> <ul class="nav navbar-nav navbar-right"> <li><a href="../" rel="external nofollow" >Home</a></li> <li><a rel="external nofollow" rel="external nofollow" rel="external nofollow" >On Github</a></li> </ul> </div><!--/.nav-collapse -->
<div class="row"> <div class="jumbotron"> <h2>中國AQI數(shù)據(jù)可視化</h2> <p>這是一個基于bottlepy, bokeh和Bootstrap的一個數(shù)據(jù)可視化部署的示例項目,采用了中國從2017年到2019年的AQI信息數(shù)據(jù)作為項目的演示數(shù)據(jù)。</p> </div> </div>
回到app.py中,在這個文件中下邊這段代碼,通過template方法實現(xiàn)了對index模板的渲染,這個方法的參數(shù)data,將作為數(shù)據(jù)動態(tài)的傳入到模板中,相對應(yīng)的模板中有一個 {{data[“developer_organization”]}} 的語句,這就是模板語法,跟python語法類似,通過dict的方式訪問了data變量中的developer_organization鍵對應(yīng)的值。
@app.route('/') def index(): data = { "developer_organization":"pythonlibrary.net"} return template('index', data = data)
3.4 啟動網(wǎng)頁服務(wù)
我們在app.py實現(xiàn)了類似下邊這樣的入口,如果在終端中運行python app.py,這段代碼將被執(zhí)行,也就可以啟動網(wǎng)頁服務(wù),服務(wù)的端口為8080,同時將host設(shè)置為0.0.0.0意思是其他電腦可以訪問這臺電腦上的服務(wù),如果僅想本機(jī)本地訪問可以設(shè)置為localhost
if __name__ == "__main__": port = 8080 app.run(host="0.0.0.0", port=port, debug=True)
4. 將Bokeh和Bottle集成在一起
4.1 模板修改
首先我們想要在html中顯示bokeh生成的圖表,需要加載bokeh的JavaScript,通過在index.tpl中添加下邊幾個CDN的方式來導(dǎo)入。
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-1.4.0.min.js"></script> <script src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script> <script src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-1.4.0.min.js"></script>
然后我們要添加數(shù)據(jù)圖表的占位符(相關(guān)的引擎語法代碼),當(dāng)進(jìn)行模板渲染的時候,會被動態(tài)的替換為python代碼中提供的內(nèi)容。
在頁面主體container中添加三個圖表的占位符
注意:有別于其他數(shù)據(jù)傳入語法,這里在data[“l(fā)ot1_div”]前邊有一個感嘆號(?。?,這個非常重要,如果沒有感嘆號意味著,傳入的數(shù)據(jù)將被認(rèn)為是字符串,在渲染的時候會被引號括起來,而我們實際想要填充在這里的是html代碼,而不是被雙引號括起來的html代碼,感嘆號就是告知引擎,我們傳入是的瀏覽器可以處理的html或者JavaScript或者css代碼。
<div class="row"> {{!data["plot1_div"]}} </div> </br></br></br></br> <div class="row"> {{!data["plot2_div"]}} </div> </br></br></br></br> <div class="row"> {{!data["plot3_div"]}} </div>
在body標(biāo)簽后邊添加繪制圖表使用的JavaScript腳本占位符
{{!data["plot_script"]}}
這里模板中未來用到的圖表div和JavaScript腳本將會由bokeh生成,并有bottle渲染,我們會在加下來這一章節(jié)說明。
4.2 Python代碼集成
將 2.2 章節(jié)中在notebook中調(diào)試成功的代碼轉(zhuǎn)換為函數(shù),并實現(xiàn)到app.py中,注意原本在notebook中顯示圖表我們使用了show(p)的方法,在網(wǎng)頁應(yīng)用中我們僅僅是通過return p將圖表對象返回,返回值將通過bottle提供的方法進(jìn)行處理。
def get_df_from_source(): ''' get dataframes from the source dataset, only take the data of some big cities ''' cities = ['上海', '北京', '杭州', '寧波', '保定', '南京', '蘇州', '深圳', '廈門', '廣州'] df = pd.read_csv(dirname+'/dataset/AQI_merged.csv') df['date'] = pd.to_datetime(df['date']) df = df.sort_values(by='date').reset_index(drop=True) df = df[df['type']=='AQI'] return df def draw_daily_AQI(mini_date, df): year = mini_date.split('-')[0] df_day = df[df['date']>=mini_date] source = ColumnDataSource(df_day) p = figure(x_axis_type="datetime", title="{}年AQI日均平均變化曲線".format(year), plot_width=1150, plot_height=400) p.line('date', '上海', line_color='blue', legend_label='上海', source=source) p.line('date', '北京', line_color='green', legend_label='北京', source=source) p.line('date', '深圳', line_color='orange', legend_label='深圳', source=source) p.legend.location = "top_right" p.add_tools(HoverTool(tooltips=[("AQI", "$y")])) return p def draw_month_AQI(mini_date, df): year = mini_date.split('-')[0] df_day = df[df['date']>=mini_date] df_day['month'] = df_day['date'].apply(lambda x: x.strftime('%Y-%m')) df_month = df_day.groupby(by='month').mean().reset_index() source = ColumnDataSource(df_month) p = figure(x_range=list(df_month['month']), title="2019年AQI", plot_width=1150, plot_height=400) p.vbar(x=dodge('month', -0.25, range=p.x_range), top='上海', width=0.2, color="#c9d9d3", legend_label="上海", source=source) p.vbar(x=dodge('month', 0, range=p.x_range), top='北京', width=0.2, color="#718dbf", legend_label="北京", source=source) p.vbar(x=dodge('month', 0.25, range=p.x_range), top='深圳', width=0.2, color="#e84d60", legend_label="深圳", source=source) p.xgrid.grid_line_color = None p.y_range.start = 0 p.add_tools(HoverTool(tooltips=[("時間", "@month"), ("上海平均AQI", "@{上海}"), ("北京平均AQI", "@{北京}"), ("深圳平均AQI", "@{深圳}")])) return p def draw_year_AQI(df): df['date_ym'] = df['date'].apply(lambda x: x.strftime('%Y-%m')) df_month = df.groupby(by='date_ym').mean().reset_index() df_month['month'] = df_month['date_ym'].apply(lambda x: x.split('-')[-1]) df_month['year'] = df_month['date_ym'].apply(lambda x: x.split('-')[0]) df_2017 = df_month[df_month['year']=='2017'][['month', '北京']] df_2018 = df_month[df_month['year']=='2018'][['month', '北京']] df_2019 = df_month[df_month['year']=='2019'][['month', '北京']] source_2017 = ColumnDataSource(df_2017) source_2018 = ColumnDataSource(df_2018) source_2019 = ColumnDataSource(df_2019) p = figure(x_range=list(df_2017['month']), title="2017-2019年北京AQI對比", plot_width=1150, plot_height=400) p.vbar(x=dodge('month', -0.25, range=p.x_range), top='北京', width=0.2, color="#c9d9d3", legend_label="2017", source=source_2017) p.vbar(x=dodge('month', 0, range=p.x_range), top='北京', width=0.2, color="#718dbf", legend_label="2018", source=source_2018) p.vbar(x=dodge('month', 0.25, range=p.x_range), top='北京', width=0.2, color="#e84d60", legend_label="2019", source=source_2019) p.xgrid.grid_line_color = None p.y_range.start = 0 p.add_tools(HoverTool(tooltips=[("時間", "@month"), ("AQI", "@{北京}")])) return p
三個繪圖函數(shù)返回了圖表對象p,我們?nèi)绻軌蜃宐ottle來渲染圖表對象,從而實現(xiàn)在網(wǎng)頁中的圖表展示呢?bokeh提供了一個components方法,可以接收圖表對象作為參數(shù),而返回繪圖使用的JavaScript腳本和圖表div,因此修改我們的index路由函數(shù)為:
@app.route('/') def index(): df = get_df_from_source() plot1 = draw_daily_AQI('2019-01-01', df=df) plot2 = draw_month_AQI('2019-01-01', df=df) plot3 = draw_year_AQI(df=df) plots_data = components((plot1, plot2, plot3)) data = { "plot_script":plots_data[0], "plot1_div":plots_data[1][0], "plot2_div":plots_data[1][1], "plot3_div":plots_data[1][2], "developer_organization":"pythonlibrary.net"} return template('index', data = data)
在這里,index.tpl模板中的data字典中的plot1_div,plot2_div,plot3_div以及plot_script將被動態(tài)的渲染替換。最終實現(xiàn)了將圖表展示在網(wǎng)頁上的目的。
你可以clone本項目的倉庫來嘗試運行,或者直接訪問http://china-aqi-data-visulazition.herokuapp.com/來查看效果
5. 部署應(yīng)用到Heroku
這部分內(nèi)容跟怎么將數(shù)據(jù)圖表展示在網(wǎng)頁上沒有直接的關(guān)系,僅僅是一種可選的免費云服務(wù),可以供你來共享你的頁面,或者了解網(wǎng)頁部署。但其實不同的服務(wù)可能部署的方式并不相同,因此如果你要部署你的網(wǎng)頁到其他服務(wù)提供商,可能這里的知識完全不適用。
在Heroku上用戶可以免費部署有限的網(wǎng)絡(luò)應(yīng)用,同時過程也非常的簡單,只需要實現(xiàn)一個Procfile文件,Heroku系統(tǒng)就知道怎么運行你的服務(wù)了。我們的項目中Procfile使用如下代碼,跟我們本地運行服務(wù)類似。
web: python app.py
而針對app.py的入口代碼,需要將port改為從環(huán)境變量讀取,因為Heroku會動態(tài)的為應(yīng)用分配端口,如果指定一個固定值,則會因為Heroku沒有打開其的對外訪問,而導(dǎo)致用戶無法訪問該服務(wù)。
if __name__ == "__main__": port=int(os.environ.get("PORT", 8080)) app.run(host="0.0.0.0", port=port, debug=True
最后用戶可以在Heroku頁面上選擇將github倉庫和應(yīng)用連接在一起,那么系統(tǒng)會自動的從github拉取最新代碼然后啟動服務(wù)。
6. 參考文檔
https://docs.bokeh.org/en/latest/docs/reference/models/plots.html
https://docs.bokeh.org/en/latest/docs/reference/embed.html
https://bottlepy.org/docs/dev/
更多關(guān)于python數(shù)據(jù)可視化的教程請查看下面的相關(guān)文章
相關(guān)文章
python實現(xiàn)發(fā)送和獲取手機(jī)短信驗證碼
這篇文章主要介紹了python實現(xiàn)發(fā)送和獲取手機(jī)短信驗證碼的相關(guān)資料,講解了python如何解決接口測試獲取手機(jī)驗證碼問題,感興趣的小伙伴們可以參考一下2016-01-01Python實現(xiàn)數(shù)據(jù)地址實體抽取
大家好,本篇文章主要講的是Python實現(xiàn)數(shù)據(jù)地址實體抽取,感興趣的同學(xué)趕快來看一看吧,對你有幫助的話記得收藏一下2022-02-02Python隨機(jī)數(shù)random模塊使用指南
本文給大家分享的是Python隨機(jī)數(shù)random模塊的幾個常用的方法,非常的簡單,小伙伴們喜歡的話,后續(xù)繼續(xù)深入探討2016-09-09Python實現(xiàn)判斷并移除列表指定位置元素的方法
這篇文章主要介紹了Python實現(xiàn)判斷并移除列表指定位置元素的方法,涉及Python針對列表的索引范圍判斷及元素刪除等相關(guān)操作技巧,需要的朋友可以參考下2018-04-04Python實現(xiàn)冒泡排序的簡單應(yīng)用示例
這篇文章主要介紹了Python實現(xiàn)冒泡排序的簡單應(yīng)用,結(jié)合實例形式分析了Python基于冒泡排序?qū)崿F(xiàn)的輸入字符串?dāng)?shù)字排序與運算操作,需要的朋友可以參考下2017-12-12從DataFrame中提取出Series或DataFrame對象的方法
今天小編就為大家分享一篇從DataFrame中提取出Series或DataFrame對象的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-11-11