过去两天我在自己的 fork 上给 vscode-R 的 httpgd 画图预览做了点修改,主要是两件事:支持选择输出格式(SVG/PNG),以及修一下在新加入的位图情况下在高分屏/多显示器上把清晰度和缩放问题。
TL;DR
- 画图格式现在可以选 SVG(svgp) 或 PNG;
- HiDPI 修复:对 PNG 这种位图渲染会按 设备像素比(DPR) 放大请求的宽高,同时把 zoom (缩放等级) 也一起乘上 DPR,这样图标/文字大小在缩放时不会显得过小,移动窗口到不同 DPI 的屏幕也会自动刷新,保持清晰。
- 切换历史图更快:加了一个按 plot id + 尺寸 + 缩放 + dpr + 渲染器 组合键的缓存;也确保图像大小变化的时候会正常重绘。难以想象之前官方版插件居然没有缓存()
1)加入位图让数据点太多的图流畅点
这次改动的直接动机,是在做单细胞 RNA-seq 分析时,散点图的数据点可能有几十万,httpgd 当前是只能用 SVG,会吃一吨内存而且卡得不能动。虽然 SVG 在矢量清晰度上有优势,但在这种点数爆炸的情况下,DOM 元素数量巨大,渲染和交互都非常慢。
这个问题我本来几百年前就想解决一下,但是当时想复杂了,想着要自己实现一下 SVG 的浏览器GPU加速渲染,这对我来说就肯定搞不定了… 但前两天发现 httpgd 其实本来就支持 png 输出… 之前想太复杂了。
2)位图的适应屏幕分辨率
位图在高分屏上如果直接用逻辑像素请求,会显得模糊。SVG 是没有这个问题的,因为它本来就是矢量的。我在前端把 devicePixelRatio(DPR)带给后端,请求时按 width * dpr / height * dpr 去生成位图。同时,把 zoom 也一起乘上 dpr,这样放大后文字和标记的视觉大小保持一致,只是清晰度提升。
如果窗口被拖到另一台 DPI 不同的显示器,DPR 变化会触发一次刷新,即使宽高没变也会重绘,从而保证始终是高清的。
3)历史图缓存:减少重复请求
同样是因为单细胞 RNA-seq 大图加载慢的问题,加了一层缓存:
- key:
plotId + width + height + zoom + dpr + renderer - 命中直接用缓存,没命中才向
httpgd请求重绘 - 在重置图、关闭图、DPR 改变时会清空缓存,避免拿旧图
- 缓存上限固定为 50 张,应该是够了的
这样在切换历史图时,已经加载过的 PNG 或 SVG 会立即显示出来,不必再次等待 httpgd 渲染。
如果你也想试试
- 去这里下载 zip 文件并解压:下载链接
- 卸载旧的官方版
reditorsupport.r插件。 - 按
Ctrl+Shift+P(或 macOS 上的Cmd+Shift+P),搜索Extensions: Install from VSIX,选择刚解压的 VSIX 文件安装。 - 在设置里打开 vscode://settings/r.plot.useHttpgd
- 在设置里打开 vscode://settings/r.plot.defaults.httpgdRenderer 并设置成
png - 另外提醒,如果是在服务器上画图,要在服务器端也安装这个改过的插件版本。
如果官方把 PR 合并了就不用这么麻烦了,就可以直接装官方的。但看上去几个主要的 maintainer 都不太活跃,可能暂时合不进去了。
然后就没了,可以去画个大图试试。下方是我随意画的 1e5 个点的图,完全不卡。

对了在这里还要感谢 AI 大爹,这些改动基本都是 copilot 帮我搞定的,我就是看他哪里老写出来有bug手动修一下。这个文章也是把 commit 记录扔给 ChatGPT 帮我写的初稿我再改的。
Update: unigd 的 conda 包
给实验室同学安排这个版本的发现在他那里不能正常工作,调查一番之后找到问题是 conda-forge 里的 unigd 包(这是 httpgd 的重要依赖,绘图后端)缺少了一些重要依赖,导致 unigd 无法渲染位图。而我当时开发时使用的 httpgd 版本正好没有这个问题,所以没有发现。
办法:
- 直接用旧版
1.3.1的httpgd。 - 我重新打了
unigd的包放在了我自己的 channel. 安装httpgd时多指定这个 channel 应该就会从这里拉取unigd依赖。
Last modified on 2025-08-12