用Python將股票資料視覺化 Plotly套件篇

2022/06/20閱讀時間約 13 分鐘
這是很久以前嘗試過的股票資訊視覺化的小專案,主要是參考自FINVIZ的美股TreeMap發想而來的。在Plotly的說明網站中看到了Sunburst的圖表,便試著按照一樣的邏輯試做了一次。
這篇會大致介紹製作流程,以及如何將互動圖表輸出並嵌入wordpress之中。
順便教你怎麼違反facebook的社群規則(?)

先看看成果怎樣

用成交金額來看看每天台股的變化也是個視覺化的選擇喔
方格子看起來沒辦法用html語法直接內嵌互動網頁,所以就麻煩點進去看一下囉

會使用到的環境

  • Python:3.7.10
  • requests: 抓取網頁
  • pandas:資料處理用
其他還有部分套件跟資料存取的位置有關,不過這因人而異就不列來這邊了

一樣先從爬蟲開始

有關台股的爬蟲教學很多,所以這邊不再贅述
但還是稍微提醒一下,網路上的爬蟲教學大多以爬取上市股票為主,也就是到證交所爬取每日收盤資訊,但上櫃的股票資訊得到櫃買中心爬取。要注意的是,日期格式的部分,櫃買中心的年份是以民國年組成的,所以要自己另外將年分 -1911。另外還有要注意的地方是,證交所的資料如果非交易日會爬不到資料,但櫃買中心不會,沒注意到的話會爬到一堆有股號但沒有任何交易數字的檔案,要記得檢查爬取到的資料內容。

爬取台股上市櫃股票分類

這次就不搞啥爬取後整理再輸出的過程了,直接用python的資料處理神氣pandas套件吧!
爬取的目標網站是台灣證券交易所的證券編碼
點擊證券編碼分類查詢,在市場別這邊選取上市以及上櫃的分類,並將網址複製下來
那接下來就簡單囉,先引入套件並把剛剛拿到的網址存下來
import requests
import pandas as pd

TWSE_URL = 'http://isin.twse.com.tw/isin/C_public.jsp?strMode=2' # 上市市場
TPEX_URL = 'http://isin.twse.com.tw/isin/C_public.jsp?strMode=4' # 上櫃市場
上面的網址會指向整個市場上有交易的商品,所以在篩選的證券別那裡可以依自己想要爬取的資料再作選取,那因為主要是做股票的資料視覺化,拿股票資料就好咧
以上是上市股票的查詢結果,可以發現主要是以表格的形式呈現資料,因此我們可以用pandas內建的函式read_html來爬取表格
read_html()的這個方法主要是抓取html中的<table>表格標籤,並將爬到的表格回傳為DataFrame物件(總之就是資料表啦)
res = requests.get("https://isin.twse.com.tw/isin/class_main.jsp?owncode=&stockname=&isincode=&market=1&issuetype=1&industry_code=&Page=1&chklike=Y")
df = pd.read_html(res.text)[0]
# 資料都在第一個表格裡
把爬取到的表格書出來看看
以上可以看到資料都完整的爬下來了,但欄位名稱有點跑掉了,雖然在讀取的時候可以用其他的參數設定,但在輸出之前很少會先知道爬下來的東西長怎樣,所以建議還是輸出後再做資料清理
# 設定column名稱
df.columns = df.iloc[0]
# 刪除第一行
df = df.iloc[1:]
上櫃股票跟上市股票的步驟一模模一樣樣,這樣包含我原先準備好的收盤數據,資料都準備好了,開始作圖吧

作圖用的DataFrame

這次用來作圖的套件為Plotly,所使用的是plotly.express的API,這個API可以讓使用者用很簡單的方式就做出炫砲的圖
使用者只須要把想輸出的資料準備好就行了
從開頭的範例可以看出,我們需要的資料有 證券代號、市場別、產業別以及各個股票的名稱。所以這邊我們很簡單地把需要的資料準備好
# 這邊是使用dict的方式創建一個新的DataFrame
dff = pd.DataFrame({
'stock_id': info['有價證券代號'],
'county': 'TW-Stock', # 用來把下面的路徑包起來
'label': info['label'],
'market': info['市場別'],
'category': info['產業別']
})
在這段程式碼裡我加了一段'county': 'TW-Stock',主要目的是將路徑包起來,可以想像成是一種資料夾的概念,把分類的東西放到同個資料夾裡面。至於為什麼取名叫county而不是country呢? 因為我拼錯了
另外要提的是'label'的這個欄位,這個欄位是用來標示圖上顯示的名字用的,我很單純地用股號跟證券名稱組在一起,可以依喜好自行搭配
接下來加上當天股價、當天漲跌幅以及成交金額就大功告成啦
當天漲跌幅的計算方式為將當天收盤價減去前一個交易日的收盤價除前一交易日收盤價,這邊沒附上程式碼的原因是我資料亂放的關係,所以把收盤價取出來的過程看起來很雜亂,而且我也沒很想重寫
在以上輸出的圖中可以發現stock_id的位置明顯跟其他欄位不一樣,這是因為在取資料的時候我把stock_id作為index去匹配,傳給Plotly的API前要記得reset_index()把它取消,不然API會沒辦法取用df的資料
另外要提醒的是,有些股票沒有人交易,資料的股價可能會出現nan沒有資料的情形。圖一樣可以做出來,但顏色會因此跑掉呈現灰色或是黑色,所以這邊就把沒有數據的資料直接丟棄

Sunburst作圖

接下來開始作圖囉
import plotly.express as px


fig = px.sunburst(
dff,
path=['county', 'market', 'category','label'],
values='成交金額',
color='當天漲跌幅',
color_continuous_scale=[(0, "green"), (0.25, 'green'), (0.5, "#f7f7f7"), (0.75, "red"), (1, "red")],
color_continuous_midpoint=0,
maxdepth=2,
range_color=[-10.0, 10.0],
width=1350,
height=900,
title='2022/6/17台股成交圖'
)
fig.update_traces(
textinfo="label+percent entry", selector=dict(type='sunburst'), textfont=dict(size=18)
)

fig.update_traces(textfont_size=14)
首先介紹什麼是sunburst,sunburst翻成中文為從雲隙間射入的陽光,好像太詩情畫意了點。總之就是類似陽光的散射圖,是傳統的圓餅圖再升級版。主要特色在於,可以將資料的層級歸屬關係表現出來,越接近中心點的資料表示資料層級愈高。
接下來說明一下上面的程式碼在幹嘛
用px.sunburst()的API建立起一個容器,傳進事先準備好的資料dff
接著用path來告訴API,圖的層級順序,依照最高層級開始寫入,這邊要注意的是層級順序錯了的話,程式是無法運行的
在value的部分是類似於圓餅圖的用法,成交金額越大佔的比例就越大,而color則是告訴API顏色要依據哪個欄位的數字來設定顏色的不同 (如果欄位中有資料的數值不存在會直接賦予灰色)
color_continuous_scale為顏色的色階,可以用Plotly內建的其他樣式。但我個人經驗是,用內建的樣式,可能顏色太豐富而使圖輸出極慢,而且筆電燙到可以煎蛋。所以我是用自己刻色階的方式來取代,而color_continuous_midpoint則表示色階的中間點,也就是數值的中心點。range_color將色階的範圍固定在指定的範圍內,這邊給定的範圍是漲跌10%的範圍。
maxdepth,這是將sunburst各層級包起來所需要調用的參數,如果沒有設定的話,sunburst會直接展開來,也不是不行就不太好看就是了。maxdepth的數字決定包起來的層級有多少。
接下來的就滿直觀的吧,width寬度、height高度和title圖的標題名稱。比較需要提的是後面的update_traces(),這邊主要是用來設定文字要怎麼顯示
textinfo="label+percent entry"
這段的label跟dff的label不是同個東西,它是plotly函數的參數選項意旨為標籤,這邊的寫法是以顯示標籤加上該標籤的數值百分比,後面空一格加上entry則表示點開sunburst圖之前要顯示的文字參照路徑
更多相關的設定參數請看官方的文件,關於文字的顯示方式寫在texttemplate
然後,就完成了一個以成交金額為參考指標的陽光散射圖啦
方格子看起來沒辦法用html語法直接內嵌互動網頁,所以就麻煩點進去看一下囉

那怎麼嵌入wordpress呢?

做好的圖不輸出出來分享就太可惜了,plotly內建的函示 write_image() 可以將圖存下來到電腦裡
但好不容易做出能夠互動的炫泡圖,弄成一個不會動的JPG實在有點浪費,所以可以用 write_html() 將圖輸出成html檔,這樣就可以透過瀏覽器來互動看資料啦
那要怎麼輸出可互動的圖給wordpress咧?
有幾種方式,這邊舉兩種我試過的方式

生成div區塊的html

可以用plotly內建的線下輸出
import plotly as plt
plt.offline.plot(fig, include_plotlyjs=False, output_type='div')
output_type設定為div會生成一段div標籤的html文字,把這段文字複製起來,然後在網頁的html文檔中於想輸出的位置貼上。
但我在這邊卡關了,輸出後的中文字會變成unicode也就是斜線+數字的組合,看得出來是編碼問題,可官方文件中找不到哪邊可以調整,於是在半小時的掙扎後就放棄這個方式了。如果能解決編碼問題,這個方式會簡單許多。

或乾脆弄個網頁崁進去吧

另一種方式為,把產生的html丟到某個網站空間上,然後用<iframe>的標籤來把網頁崁進wp中
這邊我所使用的是github page的頁面
<iframe scrolling="yes" style="zoom:50%" src="https://dow1226.github.io/stock-plotly-test/" height="1280" width="960"> </iframe>
只要將src的部分修改為存放html檔案的網址就行了
這邊要特別提醒一下,這麼做的話,只要網址連結的位置圖改了或是有任何異動,都會對這個崁進來的框架產生影響喔

題外話

雖說要經營部落格,但真的要寫文章的時候惰性又來了。要不是FB鎖我文,讓我氣到動力來了,不然還真不知道要寫些什麼東西
啊,對了。沒提到怎麼違反社群守則的部分,其實很簡單啦。我就只是把github page的連結分享出去,然後說「這是股票資料做的視覺圖喔。」接著就收到以不實資訊詐騙的警告了(?)
不說這些了,你相信這個奇怪的小東西在亞馬遜上面賣41.98美元嗎? (來自youtube廣告)
為什麼會看到廣告
DowDow
DowDow
DowDow 本名范哲瑋 現在是無所事事的小業務人員 只會發布些學習紀錄跟雜談喔 wordpress連結:https://wodadow.com/ 聯絡信箱:[email protected]
留言0
查看全部
發表第一個留言支持創作者!