XY – 快速、可组合、GPU 加速的 Python 图表库 (alpha)
XY – 快速、可组合、GPU 加速的 Python 图表库 (alpha)
XY 概览
XY 是一个处于 alpha 阶段、经过 GPU 加速的 Python 图表库,适用于 Web、Notebook 和静态导出。它支持声明式或 matplotlib 风格的图表组合,并允许使用 Python、CSS 或 Tailwind 进行完全自定义。小型图表会将每个点发送到浏览器;大型图表则使用 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 万个点时超过 2.5 秒。
内存占用
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 计算步骤会根据可见视口生成直接表示、抽样表示或密度表示。发送到浏览器的负载是紧凑的 JSON 规范加上类型化二进制缓冲区。浏览器渲染 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 图 (250k 颗恒星)
- gnomAD v4.1 等位基因频率 (164k 变异)
- Pan-UKBB Manhattan 图 (814k 变异)
- Dukascopy EUR/USD ticks (101k ticks)
- LIGO GW150914 strain (16,777,216 个原始样本,显示 3,441 个)
- NYC TLC 出租车接送密度 (300k 条记录)
- 本地 OpenStreetMap 示例 (10,000,000,000 个节点) 每个 notebook 都可以进一步扩展,并包含来源说明和工作负载控制。
路线图与未来工作
计划中的功能(不按先后顺序)包括:
- 分类分布:strip, swarm, beeswarm, boxen, rug
- 回归诊断:trendline, residual, QQ, PP
- 散点矩阵和联合图:SPLOM, pair grid, marginal histograms
- 饼图 / 环形图(从
xy.pyplot提升) - K 线图 / OHLC 及金融叠加层:SMA, VWAP, Bollinger, RSI, MACD
- 瀑布图和漏斗图
- 矩形树图、旭日图和冰柱图
- 雷达图 / 极坐标图和仪表盘(需要极坐标轴)
- 斜率图、凸起图和哑铃图
- 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 rendering)方面的潜力:
"使用 XY 可以实现脱离内存渲染数据,使其能够以亚秒级的平移/缩放渲染整个 OpenStreetMaps(那是 10,742,674,832 个节点!)。在线托管有点困难,但你可以在本地尝试一下" — @adhami