grid包是一个底层的绘图系统,能够灵活地控制图形输出的外观和布局,但是grid包不提供创建完整图形的高级绘图系统,例如,ggplot2和lattice,而是提供绘制开发这些高级绘图的基础接口,
比如我目前的业务需求恰好就是常常ggplot 的个性定制无法满足,因此这里作出一些尝试。先从简单的入手。
grob 用来控制grid 绘图的主要元素,包括以下方法:circleGrob, linesGrob, polygonGrob, rasterGrob, rectGrob, textGrob, segmentsGrob, legendGrob, xaxisGrob, and yaxisGrob
可见,不仅是常用的一些图形元素linesGrob、rectGrob等,还有图例legendGrob以及坐标xaxisGrob。
此外,除了grid 可以创建grob 对象外,还有其他包包括gridExtra 也可以创建grob 对象如tableGrob。
我们可以直接通过上述的grob 方法创建对应的grid 对象,比如:
my_circle <- circleGrob(x = 0.5, y = 0.5, r = 0.5,
gp = gpar(col = "gray", lty = 3))
grid.draw(my_circle)
不同于ggplot 中,我们直接在图形对象中给如col, alpha 等图形元素赋值或通过aes 设置变量,grob 对象,通过gpar 函数进行设置,并将结果赋值给gp 参数。
这里可以复习一下这些元素:color (col
), fill (fill
), transparency (alpha
), line type (lty
), line width (lwd
), line end and join styles (lineend
and linejoin
, respectively), and font elements (fontsize
, fontface
, fontfamily
).
此外,grob 对象绘图,需要使用专门的绘图语句,比如grid.draw
或是cowplot 包中的ggdraw
。
这里建议只选用grid.draw
进行操作,二者还是存在一些差别的。
我们可以使用grid.edit
函数,实时对grid 画板上的grob 对象进行修改:
my_circle <- circleGrob(name = "my_circle",x = 0.5, y = 0.5, r = 0.5,
gp = gpar(col = "gray", lty = 3))
grid.draw(my_circle)
my_rect <- rectGrob(x = 0.5, y = 0.5, width = 0.8, height = 0.3)
grid.draw(my_rect)
grid.edit("my_circle", gp = gpar(col = "red", lty = 1))
不过需要注意的是,这里Grob/grid 对象在创建的时候,需要设置name 属性,且grid.edit 必须得对经过grid.draw 投递到画板上的grid 对象操作,否则会报错:
> dev.off()
> my_circle <- circleGrob(name = "my_circle",x = 0.5, y = 0.5, r = 0.5,
+ gp = gpar(col = "gray", lty = 3))
> grid.edit("my_circle", gp = gpar(col = "red", lty = 1))
Error in editDLfromGPath(gPath, specs, strict, grep, global, redraw) :
不存在'gPath'(my_circle)
其实ggplot 对象,也是基于grid 系统制作的,所以我们也可以用grid.draw
来绘制ggplot 对象:
wc_plot <- ggplot(cars, aes(x = speed, y = dist)) +
geom_point()
grid.draw(wc_plot)
那么,我们可不可以通过grid.edit
来个性化修改ggplot 上的元素呢?留个坑。
比较简单的是,如果我们再次运行先前的grid 语句,新的grid 会覆盖上去:
wc_plot <- ggplot(cars, aes(x = speed, y = dist)) +
geom_point()
grid.draw(wc_plot)
my_circle <- circleGrob(name = "my_circle",x = 0.5, y = 0.5, r = 0.5,
gp = gpar(col = "gray", lty = 3))
grid.draw(my_circle)
“啪的一声,很快啊,就来填坑了。”
但是,ggplot 对象并不是像grob 声明函数一样,我们在创建的时候,对其每个元素都进行name 属性的定义的。这不仅麻烦,也没有必要。
那我们该如何对它们进行编辑呢?
这里主要使用force + ls 的组合:
grid.force() # 将grob 对象拆分
grid.ls()
layout
background.1-9-12-1
panel.7-5-7-5
grill.gTree.323
panel.background..rect.314
panel.grid.minor.y..polyline.316
panel.grid.minor.x..polyline.318
panel.grid.major.y..polyline.320
panel.grid.major.x..polyline.322
NULL
geom_point.points.310
NULL
panel.border..zeroGrob.311
spacer.8-6-8-6
spacer.8-4-8-4
spacer.6-6-6-6
spacer.6-4-6-4
axis-t.6-5-6-5
axis-l.7-4-7-4
NULL
axis
axis.1-1-1-1
GRID.text.330
axis.1-2-1-2
axis-r.7-6-7-6
axis-b.8-5-8-5
NULL
axis
axis.1-1-1-1
axis.2-1-2-1
GRID.text.326
xlab-t.5-5-5-5
xlab-b.9-5-9-5
GRID.text.334
ylab-l.7-3-7-3
GRID.text.337
ylab-r.7-7-7-7
subtitle.4-5-4-5
title.3-5-3-5
caption.10-5-10-5
tag.2-2-2-2
上面的便是按照具体的元素,进行拆分后的各个元素的名称了,比如下面的x坐标轴文本是GRID.text.334
,绘图的点就是geom_point.points.310
。
我们尝试edit 他们从一下:
grid.edit("geom_point.points.310", gp = gpar(col = "red"))
grid.edit("GRID.text.334", gp = gpar(fontface = "bold"))
此外,我们还可以还直接通过ggplotGrob
方法,将ggplot 对象转换为grob 对象。
上述的步骤里,我们通过grid.force
,将ggplot 的grob 元素进行了拆分,那么我们可否将我们自行创建的grob 对象组合呢?
这里可以使用ggplot 包里的方法gTree
,将grob 对象组合:
candy <- circleGrob(r = 0.1, x = 0.5, y = 0.6,
gp = gpar(col = "pink",
lty = 3,
lwd = 2))
stick <- segmentsGrob(x0 = 0.5, x1 = 0.5, y0 = 0, y1 = 0.5, gp = gpar(lwd = 2))
lollipop <- gTree(children = gList(candy, stick))
grid.draw(lollipop)
使用gList 将各个对象传递给children。
那么我们能否将grob 对象转换成ggplot 可以操纵的样子呢?
参见:R 数据可视化 —— grid 系统(二) - 名本无名的文章 - 知乎 https://zhuanlan.zhihu.com/p/371124820
我们除了先通过对象函数创建grob 对象,再通过draw 语句绘图外,还可以直接指定输出,并通过name 来设置名称,比如:
grid.points(iris$Petal.Length, iris$Petal.Width,
name = "my_point")
[1]4.5 The grid Package | Mastering Software Development in R (bookdown.org): https://bookdown.org/rdpeng/RProgDA/the-grid-package.html#overview-of-grid-graphics
[2]R实战:grid包 - 悦光阴 - 博客园 (cnblogs.com): https://www.cnblogs.com/ljhdo/p/4874785.html
[3](11条消息) R语言grid包使用笔记——viewport_数据之美-CSDN博客_r语言grid包: https://blog.csdn.net/vivihe0/article/details/47188329