我认为你设置了自己不会得到答案的问题。你写道:
“我期望得到一个扩展ggplot2的答案,允许导出具有栅格化图层的绘图,而对现有绘图命令的更改最小,即作为geom_…命令的包装器或这些命令的附加参数,或者作为ggsave命令的一部分,它需要绘图命令的未评估部分列表(每隔一次进行栅格化),而不是提供在链接问题中提供的hacky解决方法。”
这是一个主要的开发工作,可能需要高技能开发人员数周甚至更长时间的努力。由于Stack Overflow问题,没有人会这样做。如果没有实现,我将在此处描述如何实现您所要求的内容以及为什么这相当具有挑战性。
主要参与者
让我们从我们将要处理的主要参与者开始。在最高层上是ggplot2库。它接受数据框并将其转换为图形。ggplot2本身并不知道任何关于低级绘图的东西。它只处理线条、多边形、文本等,将它们以图形对象(grobs)的形式交给grid库。
grid库本身是一个相当高级别的库。它也不知道太多关于低级绘图的东西。它主要处理线条、多边形、文本等,将它们交给一个R图形设备。设备进行实际绘制。
有许多不同的R图形设备。在R命令行中输入?Devices以查看不完整的列表。有矢量图形设备,例如pdf、postscript或svg,光栅设备,如png、jpeg或tiff,以及交互式设备,如X11或quartz。显然,作为概念的栅格化仅对矢量图形设备有意义,因为栅格设备无论如何都会栅格化所有内容。重要的是,ggplot2和grid都不知道或关心您当前正在绘制的图形设备。它们处理可以在任何设备上绘制的图形对象。
理想的高级接口
高级接口应该由ggplot2的layer()函数中的rasterize选项组成。通过这种方式,可以简单地编写,例如,geom_point(rasterize = TRUE)来栅格化点图层。对于所有geoms和stats,这将透明地工作,因为它们都调用layer()。
可能的实现
我看到四种可能的实现路线,从最不可能到最不可能。
1. 理想情况下,layer()
函数会将rasterize
选项简单地传递给grid
库,后者会将其传递给图形设备,以告诉它要栅格化绘图的哪些部分。这种方法需要对图形设备API进行重大更改。我认为这不可能发生。至少在我的有生之年内不会。
2. 或者,可以编写一个新的grob类型,在绘制grob时可以按需栅格化任何任意的grob。这种方法不需要对图形设备API进行更改,但需要详细了解grid
库的低级实现。这也可能使此类图形的交互查看非常缓慢。
3. 与第二种方法相比稍微简单一些的替代方案是只在grob构建时对任意的grob进行一次栅格化,然后在每次绘制该grob时重复使用。这在交互式图形设备上会快得多,但如果交互式更改纵横比,则绘图会变形。然而,由于此功能的主要用途将是生成pdf输出(我假设),因此此选项可能已足够。
4. 最后,栅格化也可以在layer()
函数中进行,该函数可以将常规栅格grob放置到grob树中。该解决方案类似于此处描述的技术。从技术上讲,它与第3种方法并没有太大区别。无论哪种方式,都需要编写代码来对grob树进行栅格化,然后用栅格grob替换它。
技术障碍
要将grob树的部分栅格化,我们必须将它们发送到R栅格图形设备以进行渲染。但是,没有一个将其渲染到内存的设备。因此,我们必须渲染到临时文件中(例如使用png()
),然后再读回文件。这是可能的,但很丑陋。它还依赖于不保证在每个R安装中都可用的功能(如png()
)。
其次,为了将grob树的部分与整体渲染分开渲染,我们将不得不打开一个新的图形设备,除了当前打开的设备。这是可能的,但可能会导致意外的错误。我一直在处理这样的错误,例如在这里或这里中与使用此技术的代码相关的问题。实现栅格化功能的人将不得不处理这些问题。
最终,我们需要使光栅化的代码被
ggplot2
库接受,因为我们需要替换
layer()
函数,我认为没有办法从一个单独的包中完成这个功能。考虑到光栅化解决方案可能会有多么粗糙(参见前两段),这可能是一个困难的任务。
dpi=600
或者dpi=1200
的分辨率保存为 png 格式的图片,可以获得相当清晰的光栅图像而不会生成巨大的文件。png 特别设计用于线条图形。 - Claus Wilke