简短的回答:似乎没有一种优雅或简单的方法来实现它,但是这里有一个变通方法。
我深入研究了 ggpairs
的源代码(在 CRAN 提供的 GGally 包源代码中),看看变量标签是如何实际绘制的。在 ggpairs.R
中相关的函数是 print.ggpairs
。结果表明,变量标签不是绘图矩阵中每个单元格中 ggplot
对象的一部分——即它们不是轴标题,这就是为什么使用 theme(axis.title.x = element_text(angle = 45)
等时不会受到影响。
相反,它们似乎是使用 grid.text
(在包 'grid'
中)作为文本注释进行绘制的。 grid.text
接受参数,包括 x、y、hjust、vjust、rot
(其中 rot
是旋转角度),以及使用 gpar
的字体大小、字体系列等等(请参阅 ?grid.text
),但目前似乎没有办法向 print.ggpairs
中传入这些参数的不同值——它们被固定为默认值。
您可以通过最初留空变量标签,然后使用修改过的 print.ggpairs
代码的相关部分进行自定义的放置、旋转和样式添加标签。我想出了以下修改。(顺便说一下,因为原始的 GGally
源代码是根据GPL-3 许可证发布的,所以这个修改也是如此。)
customize.labels <- function(
plotObj,
varLabels = NULL,
titleLabel = NULL,
leftWidthProportion = 0.2,
bottomHeightProportion = 0.1,
spacingProportion = 0.03,
left.opts = NULL,
bottom.opts = NULL,
title.opts = NULL) {
require('grid')
vplayout <- function(x, y) {
viewport(layout.pos.row = x, layout.pos.col = y)
}
numCol <- length(plotObj$columns)
if (is.null(varLabels)) {
varLabels <- colnames(plotObj$data)
} else if (length(varLabels) != numCol){
stop('Length of varLabels must be equal to the number of columns')
}
left.opts.default <- list(x=0,
y=0.5,
rot=90,
just=c('centre', 'centre'),
gp=list(fontsize=get.gpar('fontsize')))
bottom.opts.default <- list(x=0,
y=0.5,
rot=0,
just=c('centre', 'centre'),
gp=list(fontsize=get.gpar('fontsize')))
title.opts.default <- list(x = 0.5,
y = 1,
just = c(.5,1),
gp=list(fontsize=15))
if (is.null(left.opts)) {
left.opts <- left.opts.default
} else{
not.given <- names(left.opts.default)[!names(left.opts.default) %in%
names(left.opts)]
if (length(not.given)>0){
left.opts[not.given] <- left.opts.default[not.given]
}
}
if (is.null(bottom.opts)) {
bottom.opts <- bottom.opts.default
} else{
not.given <- names(bottom.opts.default)[!names(bottom.opts.default) %in%
names(bottom.opts)]
if (length(not.given)>0){
bottom.opts[not.given] <- bottom.opts.default[not.given]
}
}
if (is.null(title.opts)) {
title.opts <- title.opts.default
} else{
not.given <- names(title.opts.default)[!names(title.opts.default) %in%
names(title.opts)]
if (length(not.given)>0){
title.opts[not.given] <- title.opts.default[not.given]
}
}
showLabels <- TRUE
viewPortWidths <- c(leftWidthProportion,
1,
rep(c(spacingProportion,1),
numCol - 1))
viewPortHeights <- c(rep(c(1,
spacingProportion),
numCol - 1),
1,
bottomHeightProportion)
viewPortCount <- length(viewPortWidths)
if(!is.null(titleLabel)){
pushViewport(viewport(height = unit(1,"npc") - unit(.4,"lines")))
do.call('grid.text', c(title.opts[names(title.opts)!='gp'],
list(label=titleLabel,
gp=do.call('gpar',
title.opts[['gp']]))))
popViewport()
}
pushViewport(viewport(width=unit(1, "npc") - unit(2,"lines"),
height=unit(1, "npc") - unit(3, "lines")))
pushViewport(viewport(layout = grid.layout(
viewPortCount, viewPortCount,
widths = viewPortWidths, heights = viewPortHeights
)))
for(i in 1:numCol){
do.call('grid.text',
c(left.opts[names(left.opts)!='gp'],
list(label=varLabels[i],
vp = vplayout(as.numeric(i) * 2 - 1 ,1),
gp=do.call('gpar',
left.opts[['gp']]))))
}
popViewport()
popViewport()
pushViewport(viewport(width=unit(1, "npc") - unit(3,"lines"),
height=unit(1, "npc") - unit(2, "lines")))
pushViewport(viewport(layout = grid.layout(
viewPortCount, viewPortCount,
widths = viewPortWidths, heights = viewPortHeights)))
for(i in 1:numCol){
do.call('grid.text',
c(bottom.opts[names(bottom.opts)!='gp'],
list(label=varLabels[i],
vp = vplayout(2*numCol, 2*i),
gp=do.call('gpar',
bottom.opts[['gp']]))))
}
popViewport()
popViewport()
}
这里是调用该函数的示例:
require('data.table')
require('GGally')
require('grid')
fake.data <- data.table(test.1=rnorm(50),
test.2=rnorm(50),
test.3=rnorm(50),
test.4=rnorm(50))
g <- ggpairs(data=fake.data,
columnLabels=rep('', ncol(fake.data)))
print(g)
customize.labels(plotObj=g,
titleLabel = 'Test plot',
left.opts = list(x=-0.5,
y=0.5,
just=c('center', 'center'),
rot=90,
gp=list(col='red',
fontface='italic',
fontsize=12)),
bottom.opts = list(x=0.5,
y=0,
rot=45,
just=c('center', 'top'),
gp=list(col='red',
fontface='bold',
fontsize=10)),
title.opts = list(gp=list(col='green',
fontface='bold.italic'))
)
(这样会产生一些非常丑陋的标签 - 仅供演示用途!)
我没有尝试调整标签位置,例如在您的地理可视化示例中左侧和底部之外的其他位置,但我认为通过更改customize.labels
中“左侧”和“底部”代码片段中vplayout
的参数来完成。 grid.text
中的x
和y
坐标是相对于视口定义的,该视口将显示区域划分为网格。
pushViewport(viewport(layout = grid.layout(
viewPortCount, viewPortCount,
widths = viewPortWidths, heights = viewPortHeights
)))
调用
vplayout
确定了每个标签的位置使用哪个网格单元格。
GGally
,只需向ggpairs
添加附加参数,其默认值可与当前版本完全兼容。 - mschilli