者: 俊欣
來源:關于數據分析與可視化
今天小編來為大家安利另外一個用于繪制可視化圖表的Python框架,名叫Dash,建立在Flask、Plotly.js以及React.js的基礎之上,在創建之出的目的是為了幫助前端知識匱乏的數據分析人員,以純Python編程的方式快速制作出交互特性強的數據可視化大屏,在經過多年的迭代發展,如今不僅僅可以用來開發在線數據可視化作品,即便是輕量級的數據儀表盤、BI應用甚至是博客或者是常規的網站都隨處可見Dash框架的影子,今天小編就先來介紹一下該框架的一些基礎知識,并且來制作一個簡單的數據可視化大屏。
我們先來了解一下Dash框架中的兩個基本概念
Layout顧名思義就是用來設計可視化大屏的外觀和布局,添加一些例如下拉框、單選框、復選框、輸入框、文本框、滑動條等組件,其中Dash框架對HTML標簽也進行了進一步的封裝,使得我們直接可以通過Python代碼來生成和設計每一個網頁所需要的元素,例如
<div>
<h1>Hello World!!</h1>
<div>
<p>Dash converts Python classes into HTML</p>
</div>
</div>
我們轉化成Dash的Python結構就是
html.Div([
html.H1('Hello Dash'),
html.Div([
html.P('Dash converts Python classes into HTML'),
])
])
Callbacks也就是回調函數,基本上是以裝飾器的形式來體現的,實現前后端異步通信的交互,例如我們在點擊按鈕或者下拉框之后出現的功能就是通過回調函數來實現的。
在導入模塊之前,我們先用pip命令來進行安裝,
! pip install dash
! pip install dash-html-components
! pip install dash-core-components
! pip install plotly
然后我們導入這些剛剛安裝完的模塊,其中dash-html-components用來生成HTML標簽,dash-core-components模塊用來生成例如下拉框、輸入框等組件,這里我們還需要用到plotly模塊,因為我們需要用到的數據來自該模塊,里面是一眾互聯網公司過去一段時間中股價的走勢
import dash
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objects as go
import plotly.express as px
那么我們讀取數據并且用plotly來繪制折線圖,代碼如下
app = dash.Dash() #實例化Dash
df = px.data.stocks() #讀取股票數據
def stock_prices():
# 繪制折線圖
fig = go.Figure([go.Scatter(x=df['date'], y=df['AAPL'],
line=dict(color='firebrick', width=4), name='Apple')
])
fig.update_layout(title='股價隨著時間的變幻',
xaxis_title='日期',
yaxis_title='價格'
)
return fig
app.layout = html.Div(id='parent', children=[
html.H1(id='H1', children='Dash 案例一', style={'textAlign': 'center',
'marginTop': 40, 'marginBottom': 40}),
dcc.Graph(id='line_plot', figure=stock_prices())
])
if __name__ == '__main__':
app.run_server()
我們點擊運行之后會按照提示將url復制到瀏覽器當中便可以看到出來的結果了,如下所示
從代碼的邏輯上來看,我們通過Dash框架中的Div方法來進行頁面的布局,其中有參數id來指定網頁中的元素,以及style參數來進行樣式的設計,最后我們將會指出來的圖表放在dcc.Graph()函數當中。
然后我們再添置一個下拉框,當我們點擊這個下拉框的時候,可是根據我們的選擇展示不同公司的股價,代碼如下
dcc.Dropdown(id='dropdown',
options=[
{'label': '谷歌', 'value': 'GOOG'},
{'label': '蘋果', 'value': 'AAPL'},
{'label': '亞馬遜', 'value': 'AMZN'},
],
value='GOOG'),
output
options參數中的label對應的是下拉框中的各個標簽,而value對應的是DataFrame當中的列名
df.head()
output
最后我們將下拉框和繪制折線圖的函數給連接起來,我們點擊下拉框選中不同的選項的時候,折線圖也會相應的產生變化,
@app.callback(Output(component_id='bar_plot', component_property='figure'),
[Input(component_id='dropdown', component_property='value')])
def graph_update(dropdown_value):
print(dropdown_value)
# Function for creating line chart showing Google stock prices over time
fig = go.Figure([go.Scatter(x=df['date'], y=df['{}'.format(dropdown_value)],
line=dict(color='firebrick', width=4))
])
fig.update_layout(title='股價隨著時間的變幻',
xaxis_title='日期',
yaxis_title='價格'
)
return fig
我們看到callback()方法中指定輸入和輸出的媒介,其中Input參數,里面的component_id對應的是下拉框的id也就是dropdown,而Output參數,當中的component_id對應的是折線圖的id也就是bar_plot,我們來看一下最后出來的結果如下
最后,全部的代碼如下所示
場景是這樣的,本來是想申請一個第三方支付接口判斷用戶支付是否成功,后來發現不需要申請接口也可以通過訂單號查詢頁面獲取支付結果,這樣就可以直接解析html來判斷支付結果了,這就引入了本文的主題,Jsoup解析html
當然jsoup不只有上面的應用場景,它還有一個應用場景,就是爬蟲!
題外話:上面場景中,使用支付接口其實才是最穩當的辦法,但是支付接口申請周期長,而且一些情況下并不是免費的,再者一些支付接口只支持一種語言,可能和本項目不是一個語言(比如項目是Java的,但是人家提供的支付接口只支持PHP),這樣增加了系統復雜度,如果業務量大且要求準確的場景下應當使用支付接口,否則可以取巧解析html,解析html有一個不好的地方就是如果html結構變化了,那么接口就得重寫,都有優缺點,看場景選擇。
官網:https://jsoup.org/
jsoup 提供了簡便的API,使用了HTML5 DOM方法和CSS選擇器用來解析HTML。其實現了WHATWG HTML5 規范,像瀏覽器一樣解析HTML。
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.11.2</version>
</dependency>
String html = "<html><head><title>First parse</title></head>"
+ "<body><p>Parsed HTML into a doc.</p></body></html>";
Document doc = Jsoup.parse(html);
// 簡潔版
Document doc = Jsoup.connect("http://example.com/").get();
String title = doc.title();
//完整版
doc = Jsoup.connect("http://example.com")
.data("query", "Java")
.userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36")
.cookie("auth", "token")
.timeout(3000)
.post();
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
Element content = doc.getElementById("content");
Elements links = content.getElementsByTag("a");
for (Element link : links) {
String linkHref = link.attr("href");
String linkText = link.text();
}
String html = "<p>An <a href='http://example.com/'><b>example</b></a> link.</p>";
Document doc = Jsoup.parse(html);
Element link = doc.select("a").first();
String text = doc.body().text(); // "An example link"
String linkHref = link.attr("href"); // "http://example.com/"
String linkText = link.text(); // "example""
String linkOuterH = link.outerHtml();
// "<a href="http://example.com"><b>example</b></a>"
String linkInnerH = link.html(); // "<b>example</b>"
Document doc = Jsoup.connect("http://jsoup.org").get();
Element link = doc.select("a").first();
String relHref = link.attr("href"); // == "/"
String absHref = link.attr("abs:href"); // "http://jsoup.org/"
Jsoup支持CSS選擇器,用的是 Element.select(String selector)方法
File input = new File("/tmp/input.html");
Document doc = Jsoup.parse(input, "UTF-8", "http://example.com/");
Elements links = doc.select("a[href]"); // a with href
Elements pngs = doc.select("img[src$=.png]");
// img with src ending .png
Element masthead = doc.select("div.masthead").first();
// div with class=masthead
Elements resultLinks = doc.select("h3.r > a"); // direct a after h3
如何快速定位頁面上元素的內容?答案是打開Chrome,按F12打開開發者工具,定位到想要的DOM節點,右鍵,copy,選擇Copy selector,即可生成CSS選擇器,類似于body > div > div.content > div.col2 > div > h3:nth-child(10)
遺憾的是Jsoup不支持Xpath選擇器,但是早就有人意識到這個問題了,所以誕生了JsoupXpath
JsoupXpath 是一款純Java開發的使用xpath解析提取html數據的解析器,針對html解析完全重新實現了W3C XPATH 1.0標準語法,xpath的Lexer和Parser基于Antlr4構建,html的DOM樹生成采用Jsoup,故命名為JsoupXpath. 為了在java里也享受xpath的強大與方便但又苦于找不到一款足夠好用的xpath解析器,故開發了JsoupXpath。JsoupXpath的實現邏輯清晰,擴展方便, 支持完備的W3C XPATH 1.0標準語法,W3C規范:http://www.w3.org/TR/1999/REC-xpath-19991116 ,JsoupXpath語法描述文件Xpath.g4
項目地址:https://github.com/zhegexiaohuozi/JsoupXpath
感興趣的可以看一下測試用例:里面包含了大量的使用場景:https://github.com/zhegexiaohuozi/JsoupXpath/blob/master/src/test/java/org/seimicrawler/xpath/JXDocumentTest.java
jsoup可以在插入、刪除、提取HTML,直接看例子代碼
//設置屬性
doc.select("div.comments a").attr("rel", "nofollow");
doc.select("div.masthead").attr("title", "jsoup").addClass("round-box");
//插入html
Element div = doc.select("div").first(); // <div></div>
div.html("<p>lorem ipsum</p>"); // <div><p>lorem ipsum</p></div>
div.prepend("<p>First</p>");
div.append("<p>Last</p>");
// now: <div><p>First</p><p>lorem ipsum</p><p>Last</p></div>
Element span = doc.select("span").first(); // <span>One</span>
span.wrap("<li><a href='http://example.com/'></a></li>");
// now: <li><a href="http://example.com"><span>One</span></a></li>
//設置文本
Element div = doc.select("div").first(); // <div></div>
div.text("five > four"); // <div>five > four</div>
div.prepend("First ");
div.append(" Last");
// now: <div>First five > four Last</div>
String unsafe =
"<p><a href='http://example.com/' onclick='stealCookies()'>Link</a></p>";
String safe = Jsoup.clean(unsafe, Whitelist.basic());
// now: <p><a href="http://example.com/" rel="nofollow">Link</a></p>
人都是產品經理旗下【起點學院】推出產品經理“365天”成長計劃,BAT大牛帶你學產品!
掏出手機,打開虎嗅,開始了軟文之旅?;⑿酇PP不得不說是我了解互聯網世界的一扇窗口。
若干篇咨詢過后,停頓下來,閑暇之余,端詳這款熟悉而又陌生的面孔。
APP:虎嗅;
版本號:v2.5.0
體驗設備:iphone6;
操作系統:ios8.3;
虎嗅APP的主界面除了內容區域,最為突出的就是logo,一個漢堡菜單按鈕和一個個人中心的按鈕。首先對這款APP的漢堡菜單,進行一下簡單的初體驗。
為了更好的理解,我采用了Javascript對象的的思想去解析。
先科普一下,在 JavaScript 中,對象是擁有屬性和方法的數據。屬性是一種值,方法是執行的動作。
漢堡菜單是近年來APP比較流行的菜單方式,由于移動端設備的尺寸有限,不能將更多的區域留給除了展示內容以外的其他選項,因此漢堡菜單應用而生。它將一些功能選項隱藏在一個菜單按鈕之下,用戶不僅可以通過此菜單找到相應的功能選項,更主要的是節省了大部分的屏幕面積留作內容展示,畢竟無論是什么產品,內容為王。但是漢堡菜單也不是萬能的,也有它的缺點,那就是功能選項的曝光率低,隱藏深,不易用戶點擊。關于各種各樣導航方式的優缺點在人人都是PM社區中有提到,大家可以搜索查看。
今天我們暫且不說虎嗅APP功能選項采用漢堡菜單是否合適,我們先看一下漢堡菜單下的內容:
菜單選項下面分了六個小的功能項:看點,觀點,讀點,收藏,待讀和搜索。
看點:主要是互聯網門戶網站(比如網易科技,騰訊科技)的最新商業資訊,經過編輯精心篩選和加工上線;
觀點:大多是虎嗅注冊會員的原創文文章;
讀點:互聯網領域最新的圖書。
這三個標簽將虎嗅的內容分成了三大部分,如果以面向對象編程的思想去理解的話,這就應該是虎嗅APP內容(對象)的一個屬性,簡而言之,菜單這里的看點,觀點和讀點全都是對于整個APP內容的分類,也就是一個APP內容整體的標簽。但是,收藏和待讀這兩個功能選項(或者稱為方法)的對象卻是用戶。也就是收藏和待讀這種行為的發起者是用戶,這里感覺放在個人區域更為合適,也便于理解。
針對以上理解重新梳理一下虎嗅APP的信息架構:
此處著重說明一下為啥要將搜索功能拿出來。搜索,顧名思義,利用用戶提供的關鍵字,為用戶提供精確匹配的結果。搜索功能很多,那么就虎嗅APP的搜索功能,我想到兩種使用場景:
(1)通過關鍵詞搜索來獲取相關的文章。這是用戶通過搜索功能精確匹配自己感興趣的內容,一次來達到碎片化時間的最優化利用;
(2)通過搜索功能來獲取歷史文章。某天,我突然需要一張圖標來佐證我的觀點,而這張圖標隱隱約約在虎嗅APP上面見過,但是并不是最新的新聞資訊。一方面可以查看自己是否收藏該文,另一方面就可以利用搜索功能粗略匹配關鍵字,進而縮短查找時間。
以上就是個人對虎嗅APP的一些簡單的思考,按照上面的分析,日后繼續進行APP的界面設計,歡迎大家提出建議
*請認真填寫需求信息,我們會在24小時內與您取得聯系。