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 xyuv 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-xyuv 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

Sources