XY – 快速、可組合且具 GPU 加速功能的 Python 圖表函式庫 (alpha)
XY – 快速、可組合且具 GPU 加速功能的 Python 圖表函式庫 (alpha)
XY 概覽
XY 是一個處於 alpha 階段、具備 GPU 加速功能的 Python 圖表函式庫,適用於網頁、notebooks 以及靜態匯出。它允許使用 Python、CSS 或 Tailwind 進行宣告式或 matplotlib 風格的圖表組合與完全自定義。小型圖表會將每個點傳送到瀏覽器;大型圖表則使用 Rust 核心,根據螢幕解析度僅計算需要顯示的部分,且平移、縮放、懸停和選擇功能可以回傳精確的原始資料列。該函式庫已成功渲染了整個 OpenStreetMap——這是一個包含 10,000,000,000 個點的數據集。
安裝與基本用法
使用 pip install xy 或 uv add xy 安裝 XY。圖表由容器 (container) 和標記 (marks) 組成;任何序列皆可使用,NumPy 是選配的。例如:
import xy
chart = xy.line_chart(xy.line([1, 2, 3, 4, 5], [120, 180, 165, 240, 310]))
chart # 在 notebooks 中渲染
相同的 API 可擴展至大型數據;使用 NumPy 陣列和 density=True 旗標可以創建一個包含 1 億個點的散佈圖。
效能特性
基準測試結果顯示,XY 的渲染時間在四個數量級內保持平穩:1 萬個點時為 0.071 秒,1 億個點時為 0.081 秒。這種平穩性是因為當資料超過 20 萬列時,XY 會繪製一個受螢幕限制的密度表面,而非每列一個標記,而縮放功能可以切換回精確的資料列。精確標記路徑 (density=False) 隨規模線性增長,在 1 億個點時達到 1.34 秒。相比之下,Matplotlib 和 Plotly 的耗時大幅增加,Matplotlib 在約 300 萬個點時超過 1 秒,Plotly 在約 250 萬個點時也是如此。
記憶體使用量
XY 在 Python 端的常駐記憶體增長緩慢:1 萬個點時為 0.05 GiB,250 萬個點時為 0.13 GiB,1 億個點時為 2.58 GiB。精確標記基準 (density=False) 使用大約兩倍的記憶體(1 億個點時為 5.26 GiB)。Matplotlib 和 Plotly 在同等規模下消耗更多記憶體,在 5000 萬個點時分別達到 3.85 GiB 和無法測量。
XY 的內部運作原理
XY 在 ColumnStore 中保留標準的 f64 資料。原生的 Rust 計算步驟會根據可見視口產生直接、抽樣 (decimated) 或密度表示形式。傳送到瀏覽器的負載是緊湊的 JSON 規範加上類型化二進位緩衝區 (typed binary buffers)。瀏覽器渲染 WebGL2 標記、Canvas 座標軸和 DOM 介面。由於原始的 f64 欄位保留在 Python 中,懸停和選擇互動可以回傳原始資料列。
與 Reflex 的整合
reflex-xy 轉接器可將任何 XY 圖表轉換為一般的 Reflex 組件,無需 JavaScript、iframe 或獨立的圖表服務。使用 pip install reflex-xy 或 uv add reflex-xy 安裝。在 rxconfig.py 中註冊一次轉接器:
import reflex as rx
import reflex_xy
config = rx.Config(app_name="dashboard", plugins=[reflex_xy.XYPlugin()])
然後嵌入圖表:
import reflex as rx
import reflex_xy
import xy
signups = xy.line_chart(xy.line([1, 2, 3, 4, 5], [120, 180, 165, 240, 310]), title="Weekly signups")
def index() -> rx.Component:
return rx.card(rx.heading("Growth"), reflex_xy.chart(signups, height="320px", width="100%"))
懸停、平移和縮放功能將繼續運作;根據整合指南,支援由 Reflex 狀態、事件或即時串流驅動的圖表。
實際應用範例
該儲存庫提供了從公共來源獲取數據並視覺化多樣化數據集的 notebooks:
- Gaia DR3 HR 圖 (25 萬顆恆星)
- gnomAD v4.1 等位基因頻率 (16.4 萬個變異)
- Pan-UKBB Manhattan 圖 (81.4 萬個變異)
- Dukascopy EUR/USD 報價 (10.1 萬個 ticks)
- LIGO GW150914 應變 (16,777,216 個原始樣本,顯示 3,441 個)
- NYC TLC 計程車接送密度 (30 萬條記錄)
- OpenStreetMap 本地範例 (10,000,000,000 個節點) 每個 notebook 都可以進一步擴展,並包含來源說明和工作負載控制。
路線圖與未來工作
計劃中的功能(不按順序排列)包括:
- 分類分佈:strip, swarm, beeswarm, boxen, rug
- 回歸診斷:trendline, residual, QQ, PP
- 散佈矩陣與聯合圖:SPLOM, pair grid, marginal histograms
- 圓餅圖 / 甜甜圈圖 (從
xy.pyplot提升) - 蠟燭圖 / OHLC 與金融疊加:SMA, VWAP, Bollinger, RSI, MACD
- 瀑布圖與漏斗圖
- 樹狀圖 (Treemap)、旭日圖 (sunburst) 與冰柱圖 (icicle)
- 雷達圖 / 極座標圖與儀表板 (需要極座標軸)
- 斜率圖 (Slope)、跳動圖 (Bump) 與啞鈴圖 (Dumbbell)
- 3D 與體積:散佈圖、曲面、網格、等值面、體積視圖 完整的排序待辦清單可在圖表路線圖中查看。
社群反應 (Hacker News)
評論者強調了 Rust/Tailwind 的結合以及對該專案的熱情:
"太棒了,Rust 和 Tailwind CSS 這兩件我最喜歡的東西結合在一起。" — @farhan99
"已經被 matplotlib 卡住好幾個世紀了,學術界非常渴望這樣的改變。" — @NickyHeC
"這太棒了,可以輕易預見這會成為標準函式庫。迫不及待想看到 3D 和體積視覺化功能。" — @HoneySpoons 有些人質疑典型儀表板對 GPU 加速的必要性:
"我不認為 GPU 加速對大多數圖表使用場景來說是有意義的優勢。大多數儀表板渲染的數據量還不足以發揮作用。一旦圖表密集到渲染成為瓶頸,通常它已經擁擠到失去意義了。縮放可以證明支持更大數據集的合理性,但抽樣/視口剔除和細節層級通常可以避免繪製不必要的點..." — @kasts 其他人詢問缺失的功能或對比:
"不支援原生 GUI 嗎?" — @cozzyd
"很有趣;範例與 datashader 相比如何?" — @ahns
"這與 evilcharts 相比如何?我的主要用途是將數據映射到前端,市面上有很多很棒的函式庫。" — @kl01 少數人注意到了該函式庫進行 Out-of-core 渲染的潛力:
"使用 XY 可以進行 out-of-core 渲染,使其能夠以次秒級的平移/縮放渲染整個 OpenStreetMaps(那是 10,742,674,832 個節點!)。在線上託管有點困難,但你可以在本地嘗試一下。" — @adhami