Streamlit 的學習近尾聲, 終於輪到 Altair 了. Altair 也是 Streamlit 原生支援的互動式資料視覺化套件, 但我之前沒學過, 所以先來做個初步的測試.
Altair 是一個用 Python 撰寫, 基於 Vega-Lite 的宣告式 (Declarative) 資料視覺化套件, 可讓使用者以非常簡單與直觀的方式建立互動式圖表, 特別適合用於資料科學與資料分析, 其特點摘要如下 :
- 以網頁為基礎 : 方便嵌入網頁中.
- 與 Pandas 高度整合 : 可直接傳入 DataFrame.
- 宣告式 (Declarative) 語法 : 只需描述想要什麼圖, 不用自己畫線條或標籤.
- 互動式 : 支援縮放, 滑鼠工具提示 (tooltip), 資料過濾等功能
- 開放原始碼 : 採用 BSD 3-Clause 授權, 可免費用於商業專案中
參考 :
# https://github.com/vega/altair (源碼寄存庫)
# https://github.com/altair-viz (GitHub 網站)
Airtair 與其他 Python 資料視覺化函式庫的比較如下表 :
| 視覺化套件 | Web-based | 互動式 | 說明 |
|---|---|---|---|
| Altair | ✅ 是 | ✅ 高互動 | 簡潔的宣告式資料視覺化套件 |
| Matplotlib | ❌ 否 | ❌ 無 | 功能齊全但語法複雜, 屬於靜態圖表 |
| Plotly | ✅ 是 | ✅ 高互動 | 功能非常強大支援 3D 與互動, 但語法偏複雜 |
| Bokeh | ✅ 是 | ✅ 中等互動 | 適合大資料量, 可動態更新 |
| Seaborn | ❌ 否 | ❌ 無 | 建立於 Matplotlib 上, 可繪製美觀的靜態統計圖表 |
番外篇 : 我查維基百科發現, 原來 Altair 就是牛郎星! 現代天文學稱它為天鷹座 α 星, 它是天鷹座裡最亮的一顆星 (亮度是太陽的 10.6 倍, 亮度排名第 12), 質量為太陽的 1.7 倍, 距離地球約 16.7 光年, 隔著天河與天琴座的織女星 (天琴座 α 星, Vega) 遙遙相望. 中國古代星官 (欽天監) 稱它為河鼓二.
1. 安裝 altair 套件 :
用 pip 安裝 :
pip install altair
若已安裝可加 -U 更新為最新版 (目前是 v5.5.0) :
pip install altair -U
D:\python\test>pip install altair -U
Requirement already satisfied: altair in c:\users\tony1\appdata\roaming\python\python310\site-packages (5.1.1)
Collecting altair
Using cached altair-5.5.0-py3-none-any.whl.metadata (11 kB)
Requirement already satisfied: jinja2 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from altair) (3.1.2)
Requirement already satisfied: jsonschema>=3.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from altair) (4.19.0)
Requirement already satisfied: narwhals>=1.14.2 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from altair) (1.42.0)
Requirement already satisfied: packaging in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from altair) (24.2)
Requirement already satisfied: typing-extensions>=4.10.0 in c:\users\tony1\appdata\local\programs\thonny\lib\site-packages (from altair) (4.12.2)
Requirement already satisfied: attrs>=22.2.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jsonschema>=3.0->altair) (23.1.0)
Requirement already satisfied: jsonschema-specifications>=2023.03.6 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jsonschema>=3.0->altair) (2023.7.1)
Requirement already satisfied: referencing>=0.28.4 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jsonschema>=3.0->altair) (0.30.2)
Requirement already satisfied: rpds-py>=0.7.1 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jsonschema>=3.0->altair) (0.10.2)
Requirement already satisfied: MarkupSafe>=2.0 in c:\users\tony1\appdata\roaming\python\python310\site-packages (from jinja2->altair) (2.1.3)
Using cached altair-5.5.0-py3-none-any.whl (731 kB)
Installing collected packages: altair
Attempting uninstall: altair
Found existing installation: altair 5.1.1
Uninstalling altair-5.1.1:
Successfully uninstalled altair-5.1.1
Successfully installed altair-5.5.0
檢視版本 :
>>> import altair as alt
>>> alt.__version__
'5.5.0'
2. Altair 常用模組與元件 :
Altair 是一個基於 Vega-Lite 規範的宣告式資料視覺化套件, 核心概念是只需要描述 "資料是什麼" 以及 "想如何呈現", 不需指定 "如何畫", Altair 就會幫我們將描述自動轉換成 Vega-Lite 規格的 JSON 文件, 然後交給 Javascript 渲染成互動式圖表.
Altair 常用模組與類別等元件摘要說明如下表 :
| Altair 常用模組 & 元件 | 說明 |
|---|---|
| Chart | 最常用的圖表類別,用來建立視覺化物件 |
mark_* |
各種圖表型態,如 mark_line()、mark_bar()、mark_point() 等 |
encode() |
設定資料對應的視覺通道,例如 X 軸、Y 軸、顏色、大小、形狀等 |
transform_* |
資料轉換操作,例如 transform_filter()、transform_calculate()、transform_aggregate() |
interactive() |
啟用互動功能,如圖表縮放與滑動 |
selection_* |
設定滑鼠選取方式,如 selection_single()、selection_interval() 等 |
concat / layer |
圖表組合:水平 (+)、垂直 (&)、疊加 (alt.layer()) |
vega_datasets |
Altair 內建的測試資料集模組,如 cars、iris、stocks 等 |
utils, schema |
工具函式、JSON 格式轉換、錯誤提示與型別驗證等支援模組 |
其中 Chart 類別是 Altair 繪圖的起點, 呼叫其建構式 Chart() 並傳入要繪製的 DataFrame 會傳回一個 Chart 物件, 它就是 Altair 宣告式 JSON 繪圖設定資料的初始包裝, Chart 物件提供了一系列宣告式的方法來逐步完成繪圖目標, 每個方法都會傳回完成 JSON 更新設定後的 Chart 物件, 所以這些宣告方法可以進行鏈式呼叫 (chain calling).
整個 Altair 繪圖過程可以分解為如下 6 個宣告步驟 :
- 建立資料 : DataFrame
- 建立圖表物件 : 呼叫建構式 Chart() 並傳入 DataFrame
- 指定圖表類型 : 例如折線圖 mark_line()
- 指定欄位如何呈現 : 呼叫 encode() 方法
- 設定外觀屬性 : 呼叫 properties() 方法
- 設定互動性 : 呼叫 interactive() 方法
其中第三步的 mark_* 方法用來宣告要畫得圖表是哪一種, 支援的圖表類型如下 :
| Chart 物件方法 | 圖表類型 | 支援互動 | 說明 |
|---|---|---|---|
| mark_bar() | 長條圖 | ✅ | 用於類別數據的比較,可結合滑鼠事件或 tooltips |
| mark_line() | 折線圖 | ✅ | 顯示連續變化趨勢,可結合互動縮放、點選 |
| mark_area() | 區域圖 | ✅ | 折線下方填色,適合表達累積值,支援滑動 |
| mark_point() | 散點圖 | ✅ | 顯示資料點位置,適合 tooltip 與 selection |
| mark_circle() | 圓點圖 | ✅ | 點形為圓形,可調大小與透明度,支援互動 |
| mark_square() | 方點圖 | ✅ | 點形為方形,常與 color, size 編碼搭配 |
| mark_tick() | 刻度圖 | ⚠️ 限 | 簡單刻度符號,適合密集資料分布,不常用互動 |
| mark_rule() | 輔助線 | ✅ | 畫出直線,如平均值線,常用於 highlight 互動 |
| mark_text() | 文字 | ✅ | 加上文字標示,支援 hover 顯示或條件顯示 |
| mark_rect() | 矩形 | ✅ | 用於熱力圖,可結合滑動與 tooltips |
| mark_geoshape() | 地理圖 | ✅ | 繪製地圖形狀,支援地圖縮放與選取 |
| mark_arc() | 圓弧 | ✅ | 環狀圖/派圖常用元素,可顯示 tooltip |
| mark_trail() | 尾徑圖 | ✅ | 像是粗細變化的折線圖,適合時間序列 |
| mark_boxplot() | 盒鬚圖 | ⚠️ 限 | 描述資料分布(五數摘要),互動性有限 |
| mark_errorbar() | 誤差棒 | ⚠️ 限 | 顯示數據變異程度,多用於統計圖中 |
| mark_image() | 圖像 | ✅ | 將圖片加入圖表點位,支援互動 tooltip |
encode() 方法則是用來將資料欄位對應到圖表的視覺元素 (稱為 encoding channels), 例如 X 軸, Y 軸, 顏色, 大小, 形狀等,
| 對應名稱 | 功能 | 說明 |
|---|---|---|
| x | X 軸 | 將欄位對應至橫軸,可為時間、分類或數值資料 |
| y | Y 軸 | 將欄位對應至縱軸,通常為連續數值或比例資料 |
| color | 顏色 | 可對應分類或數值,常用於區分群組或強度差異 |
| size | 大小 | 控制點或區塊的面積大小,代表數值大小 |
| shape | 形狀 | 用不同形狀區分分類資料,僅適用於點狀圖 |
| tooltip | 提示 | 滑鼠懸停時顯示的欄位資訊,可為一個或多個欄位 |
| opacity | 透明度 | 控制視覺物件的透明程度,適合用來避免重疊 |
| text | 文字 | 在圖上顯示資料的文字標籤 |
| order | 順序 | 控制圖層堆疊順序,通常用於堆疊圖表 |
| href | 超連結 | 點擊資料點時可跳轉至指定網址,常用於地圖或報表導向 |
這些視覺元素在對應的欄位名稱後面應標示其資料型別 (通常用較簡潔的縮寫), 雖然不註明欄位型別 Altair 也會自動推斷, 但建議還是明確標示型別較好, 不僅可避免 Altair 誤判, 也可提升程式可閱讀性, 而且有些軸刻度與格式控制 (例如時間單位, 顏色比例) 需要指定正確的型別才能運作, 下表是四種欄位型別的說明 :
| 縮寫 | 資料型別全名 | 說明 |
|---|---|---|
| Q | Quantitative | 數值型資料(連續),可進行數學運算,例如價格、長度 |
| T | Temporal | 時間型資料,例如日期、時間戳記,可進行時間序列分析 |
| O | Ordinal | 有順序的分類資料,例如等級(高、中、低),但不適合數學運算 |
| N | Nominal | 無順序的分類資料,例如國家、品項名稱、性別等 |
例如下面的編碼中將 x 軸對應到資料的 data 欄位 (日期型別), y 軸對應的 price 欄位 (數值型別), 顏色則對應到 stock 欄位 (分類型別), 而提示則顯示這三欄資訊 :
alt.Chart(df).mark_line().encode(
x='date:T', # 日期,T=Temporal(時間型)
y='price:Q', # 價格,Q=Quantitative(數值型)
color='stock:N', # 股票名,N=Nominal(分類型)
tooltip=['date', 'price', 'stock']
)
第五步的 properties() 方法用來設定圖表的整體外觀屬性, 包含尺寸與標題, 以及名稱與描述 (內部 metadata 不顯示), 可用參數如下表 :
| 屬性 | 功能 | 說明 |
|---|---|---|
| width | 寬度 | 設定圖表的寬度(單位為像素,預設 300) |
| height | 高度 | 設定圖表的高度(單位為像素,預設 300) |
| title | 標題 | 設定圖表上方顯示的標題文字 |
| name | 名稱 | 用於圖表組合時的內部識別名稱 (不顯示) |
| description | 描述 | 為圖表提供說明文字(不顯示,供工具分析) |
如果要設定標題 (title), 軸 (axis), 圖例 (legend), 繪圖區 (view) 的樣式, 則需呼叫 configure_.*() 方法來調整 :
| configure_* 方法 | 用途 | 說明 |
|---|---|---|
| configure_title() | 設定標題樣式 | 標題的字型、大小、顏色、位置(例如 `fontSize=20`) |
| configure_axis() | 設定軸樣式 | 調整 x/y 軸的字型、刻度、軸線顏色、格線顯示等 |
| configure_legend() | 設定圖例樣式 | 調整圖例位置、文字大小、形狀等 |
| configure_view() | 設定繪圖區塊 | 改變背景色、框線、內邊距(padding) |
| configure() | 全域設定 | 一次設定多個層級(如 `title`, `axis`, `legend`)的樣式 |
Altair 的顏色屬性值與 Bokeh 一樣, 接受顏色名稱如 "red", 16 進位色碼例如 "#ff0000", 與 10 進位 RGB 色碼例如 "rgba(255, 0, 0, 0.5)". 關於顏色名稱可參考 Matplotlib 文件 :
最後但不是必要, 如果想要讓圖表支援基本的滑鼠縮放與平移等互動性, 可以呼叫 interactive() 方法 (無參數) 來加上此功能, 此步驟為可有可無, 通常用在時間序列的圖表 (可以放大查看某段時間) 或散布圖 (觀察密集資料點) 等, 對於靜態圖表或不希望被使用者操作的圖表則不需要.
要輸出 Altair 繪製的圖片可以呼叫 Chart 物件的 save() 方法並傳入要輸出的 .html 檔名即可. 注意, 必須是 .html 才可以, Altair 不接受 .htm 副檔名. 然後用瀏覽器開啟該 .html 檔即可到渲染結果.
3. 繪製折線圖 :
呼叫 Chart 物件的 mark_line() 方法即可繪製折線圖, 例如 :
測試 1 : 預設的折線圖 [看原始碼]
# altair-line-test-1.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line().encode(
x='x',
y='y'
)
chart.save('altair-line-test-1.html')
此例使用鏈式呼叫方式, 也可以拆成獨立的呼叫 :
chart=alt.Chart(df)
chart=chart.mark_line()
chart=chart.encode(x='x', y='y')
執行後開啟輸出檔檢視其內容可知 Javascript 利用上面程式生成的 JSON 資料繪圖 :
用瀏覽器開啟輸出的 .html 檔結果如下 :
可見預設生成 300x300 的圖片, 按右上方的互動按鈕會顯示一張選單, 可以將圖片存成 SVG 或 PNG 檔 :
點選 View Source 會開啟一個頁面顯示嵌入於網頁中的 JSON 內容 :
下面範例設定了圖片標題, 尺寸與線條的樣式 :
測試 2: 設定圖片標題, 尺寸與折線圖的線段顏色與粗細 [看原始碼]
# altair-line-test-2.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line(
color='red', # 線的顏色
strokeWidth=4 # 線的粗細 (預設 2)
).encode(
x='x:Q', # 標示資料類型為數值
y='y:Q', # 標示資料類型為數值
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖' # 圖片標題
)
chart.save('altair-line-test-2.html')
此例在呼叫 make_line() 時設定線條顏色為紅色, 線寬 4px, 在 encode() 的欄位對應有特別標示資料類型為 Q (數值) 並設定工具提示為 x, y 軸資料; 在 properties() 中則設定圖片尺寸為 400x300 與標題, 結果如下 :
下面範例設定圖片背景色與虛線線段, 背景色有兩種方式, 一是在 properties() 傳入 background 參數, 這會設定整個畫布 (包含 X, Y 軸與標題) 底色; 虛線則是在 make_line() 傳入 strokeDash 參數, 其值為一個串列 [a, b], a 是線段長度 (px), b 是空白長度 (px) :
測試 3 : 設定圖片背景色與虛線 (1) [看原始碼]
# altair-line-test-3.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line(
color='#ffff00', # 線的顏色
strokeWidth=4, # 線的粗細 (預設 2)
strokeDash=[5, 5] # 虛線 : 5px 實 5px 虛
).encode(
x='x:Q', # 標示資料類型為數值
y='y:Q', # 標示資料類型為數值
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖', # 圖片標題
background='cyan' # 背景色
)
chart.save('altair-line-test-3.html')
此例線段顏色改用 "#RRGGBB" 格式設為黃色, 結果如下 :
可見整個畫布都填滿背景色. 另一個方式是呼叫 configure_view() 傳入 fill 參數來設定繪圖區底色 (不包含軸物件), 如下面範例所示 :
測試 4 : 設定圖片背景色與虛線 (2) [看原始碼]
# altair-line-test-4.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line(
color='rgba(0, 0, 255, 0.5)', # 線的顏色
strokeWidth=4, # 線的粗細 (預設 2)
strokeDash=[10, 5] # 虛線 : 10px 實 5px 虛
).encode(
x='x:Q', # 標示資料類型為數值
y='y:Q', # 標示資料類型為數值
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖', # 圖片標題
).configure_view(
fill='lightyellow' # 僅繪圖區背景色
)
chart.save('altair-line-test-4.html')
此例線的顏色改用 "rgba(r, g, b, a)" 格式設定, 結果如下 :
可見背景色僅套用至繪圖區而已, 不包含軸物件.
標題位置預設為黑色字體置中, 可以呼叫 configure_title() 並傳入下列參數來設定樣式 :
| 參數名稱 | 預設值 | 說明 |
|---|---|---|
| anchor | 'middle' | 標題對齊方式,可選 'start'(左)、'middle'(中)、'end'(右) |
| font | 'sans-serif' | 標題字型 |
| fontSize | 10 | 字體大小(像素) |
| fontStyle | None | 字體樣式,例如 'italic' |
| fontWeight | 'normal' | 字體粗細,可為 'normal'、'bold' 或數字 |
| color | 'black' | 標題文字顏色 |
| offset | 10 | 標題與圖表內容間距(像素) |
| orient | 'top' | 標題位置(僅支援 'top') |
| limit | None | 限制標題最大寬度,超過自動換行 |
| lineHeight | None | 標題行高(適用於多行) |
例如 :
測試 5 : 設定圖片標題 [看原始碼]
# altair-line-test-5.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line().encode(
x='x:Q', # 標示資料類型為數值
y='y:Q', # 標示資料類型為數值
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖', # 圖片標題
).configure_title(
anchor='start', # 靠左
fontSize=16,
fontWeight='bold',
color='blue',
offset=15
)
chart.save('altair-line-test-5.html')
結果如下 :
可見標題已靠左, 且字體為藍色.
Altair 預設使用 x, y 軸的資料欄位名稱做為軸標籤, 如果要自訂軸標籤, 必須於 encode() 中對應軸資料欄位時, 要呼叫 alt.X() 與 alt.Y() 並傳入對應欄名與 title 參數建立軸物件來設定, 例如 :
測試 6 : 設定 X, Y 軸標籤 [看原始碼]
# altair-line-test-6.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line().encode(
x=alt.X('x', title='X 軸'), # 設定 X 軸標籤
y=alt.Y('y', title='Y 軸'), # 設定 Y 軸標籤
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖', # 圖片標題
)
chart.save('altair-line-test-6.html')
結果如下 :
軸函式 alt.X() 與 () 的參數如下表 :
| X() 與 Y() 參數 | 說明 |
|---|---|
| field | 資料欄位名稱(可省略,當做第一個位置參數) |
| type | 資料型別,如 'quantitative'、'ordinal'、'nominal'、'temporal' |
| title | 軸標籤(預設為欄位名稱) |
| scale | 控制尺度,例如 alt.Scale(domain=[0, 100]) |
| axis | 控制軸樣式,例如 alt.Axis(grid=False, title='X 軸') |
| sort | 排序資料,例如 'ascending' 或指定順序 ['A', 'B', 'C'] |
| bin | 是否將數值欄位做區間分箱,例如 True 或 alt.Bin(maxbins=20) |
| aggregate | 聚合函數,例如 'mean'、'sum'、'count' 等 |
| stack | 堆疊方式:'zero'、'normalize'、None 等 |
圖表預設是有網格的, 如果要取消網格須傳入 axis 參數並設定其值為 grid=False 的 Axis 物件 (X, Y 軸都要才會取消全部網格線), 例如 :
測試 7 : 取消網格線 [看原始碼]
# altair-line-test-7.py
import altair as alt
import pandas as pd
# 建立資料
df=pd.DataFrame({
'x': [0, 1, 2, 3, 4, 5], # x 軸資料
'y': [-5, -2, 6, 12, 4, 9] # y 軸資料
})
# 建立繪製折線圖的 Chart 物件
chart=alt.Chart(df).mark_line().encode(
x=alt.X('x', axis=alt.Axis(grid=False)), # 設定 X 軸網格線
y=alt.Y('y', axis=alt.Axis(grid=False)), # 設定 Y 軸網格線
tooltip=['x', 'y'] # 資料點工具提示
).properties(
width=400, # 圖片寬 (px)
height=300, # 圖片高 (px)
title='Altair 折線圖', # 圖片標題
)
chart.save('altair-line-test-7.html')
結果如下 :
可見網格線消失了.










沒有留言 :
張貼留言