在绘图之外、轴和绘图区域之间绘制一些东西
Draw something outside of the plot, between the axis and plot area
我有一些具有连续 X 轴和分类 Y 轴的通用图,例如:
data(iris)
p1 <-
ggplot(iris, aes(y=Species, x=Sepal.Length)) +
geom_violin()
现在我想用一些标签来注释它,这些标签应该紧挨着 Y 轴放置,使用这样一个快速而简单的解决方案:
df.labels <- data.frame(Species=c('setosa','versicolor','virginica'), Labels=c('labA','labB','labC'))
p2 <- p1 + geom_text(data = df.labels, aes(x=4, y=Species, label=Labels))
请注意,我必须明确指出 x=4
;对于更一般的情况,我做了这个功能:
add_label <- function(inpPlot, inpData, colLabel){
plotX1 <- ggplot_build(inpPlot)$layout$panel_params[[1]]$x.range[1]
plotX2 <- ggplot_build(inpPlot)$layout$panel_params[[1]]$x.range[2]
plotW <- plotX2 - plotX1
posX <- plotX1 - 0.05*plotW
colGrp <- as_label(inpPlot$mapping$y)
inpPlot +
coord_cartesian(clip='off') +
geom_text(data = inpData, aes_string(x='posX', y=colGrp, label=colLabel))
}
p3 <- add_label(p1, df.labels, 'Labels')
我不喜欢这个解决方案的地方:
- 当我调整绘图大小时,计算为“绘图宽度的 5%”的偏移量效果不佳 window(我希望轴和标签之间的绝对距离固定)
- 如果我的初始图已应用
coord_cartesian()
,则它不起作用,例如:
p1c <- p1 + coord_cartesian(xlim = c(5,NA))
p4 <- add_label(p1c, df.labels, 'Labels')
标签显示在绘图区域本身,我希望它们在绘图区域之外(但在 Y 轴“内部”,即在轴标签的右侧)。
我理想中想要的是这样的:
p5 <- add_label_good(p1c, df.labels, 'Labels')
即它应该在轴和绘图区域之间绘制标签,并且这个 space 应该是固定宽度的。
有什么办法可以做到这一点吗?
您可以考虑 patchwork
,有两个对齐的图:
library(patchwork)
plot_labels <- ggplot(df.labels, aes(x = 0, y = Species, label = Labels)) +
geom_text(hjust = 0) +
theme_void() +
theme(axis.text.y = element_text(),
axis.title.y = element_text(angle = 90, margin = margin(0,12,0,0, unit = "pt")))
plot_labels +
(p1 + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())) +
plot_layout(widths = c(1,8))
一种选择是使用面条:
p1 + facet_grid(Species~., scales = 'free_y', switch = "y",
labeller = labeller(Species = function(x) {
df.labels$Labels[match(x, df.labels$Species)]})) +
theme(text = element_text(size = 16),
strip.text.y.left = element_text(angle = 0, face = "bold",
margin = margin(10, 10, 10, 10)),
strip.background = element_blank(),
panel.spacing = unit(0, "mm"))
另一种选择是使用ggtext::element_markdown()
并使用轴文本本身作为标签:
p1 +
scale_y_discrete(labels = function(x) {
paste(x, df.labels$Labels[match(x, df.labels$Species)],
sep = paste0(rep(" ", 5), "<b>", collapse = ""))
}) +
theme(text = element_text(size = 16),
axis.text.y = ggtext::element_markdown())
对于绘图最左侧的真正 fixed-width 文本区域,您可以使用 annotation_custom
p1 +
annotation_custom(grid::rectGrob(x = unit(10, "mm"), y = 0.5,
width = unit(20, "mm"), height = 1,
gp = grid::gpar(col = NA))) +
annotation_custom(grid::textGrob(df.labels$Labels,
x = unit(10, "mm"),
y = c(0.81, 0.5, 0.19)))
我有一些具有连续 X 轴和分类 Y 轴的通用图,例如:
data(iris)
p1 <-
ggplot(iris, aes(y=Species, x=Sepal.Length)) +
geom_violin()
现在我想用一些标签来注释它,这些标签应该紧挨着 Y 轴放置,使用这样一个快速而简单的解决方案:
df.labels <- data.frame(Species=c('setosa','versicolor','virginica'), Labels=c('labA','labB','labC'))
p2 <- p1 + geom_text(data = df.labels, aes(x=4, y=Species, label=Labels))
请注意,我必须明确指出 x=4
;对于更一般的情况,我做了这个功能:
add_label <- function(inpPlot, inpData, colLabel){
plotX1 <- ggplot_build(inpPlot)$layout$panel_params[[1]]$x.range[1]
plotX2 <- ggplot_build(inpPlot)$layout$panel_params[[1]]$x.range[2]
plotW <- plotX2 - plotX1
posX <- plotX1 - 0.05*plotW
colGrp <- as_label(inpPlot$mapping$y)
inpPlot +
coord_cartesian(clip='off') +
geom_text(data = inpData, aes_string(x='posX', y=colGrp, label=colLabel))
}
p3 <- add_label(p1, df.labels, 'Labels')
我不喜欢这个解决方案的地方:
- 当我调整绘图大小时,计算为“绘图宽度的 5%”的偏移量效果不佳 window(我希望轴和标签之间的绝对距离固定)
- 如果我的初始图已应用
coord_cartesian()
,则它不起作用,例如:
p1c <- p1 + coord_cartesian(xlim = c(5,NA))
p4 <- add_label(p1c, df.labels, 'Labels')
标签显示在绘图区域本身,我希望它们在绘图区域之外(但在 Y 轴“内部”,即在轴标签的右侧)。
我理想中想要的是这样的:
p5 <- add_label_good(p1c, df.labels, 'Labels')
有什么办法可以做到这一点吗?
您可以考虑 patchwork
,有两个对齐的图:
library(patchwork)
plot_labels <- ggplot(df.labels, aes(x = 0, y = Species, label = Labels)) +
geom_text(hjust = 0) +
theme_void() +
theme(axis.text.y = element_text(),
axis.title.y = element_text(angle = 90, margin = margin(0,12,0,0, unit = "pt")))
plot_labels +
(p1 + theme(axis.title.y = element_blank(),
axis.text.y = element_blank())) +
plot_layout(widths = c(1,8))
一种选择是使用面条:
p1 + facet_grid(Species~., scales = 'free_y', switch = "y",
labeller = labeller(Species = function(x) {
df.labels$Labels[match(x, df.labels$Species)]})) +
theme(text = element_text(size = 16),
strip.text.y.left = element_text(angle = 0, face = "bold",
margin = margin(10, 10, 10, 10)),
strip.background = element_blank(),
panel.spacing = unit(0, "mm"))
另一种选择是使用ggtext::element_markdown()
并使用轴文本本身作为标签:
p1 +
scale_y_discrete(labels = function(x) {
paste(x, df.labels$Labels[match(x, df.labels$Species)],
sep = paste0(rep(" ", 5), "<b>", collapse = ""))
}) +
theme(text = element_text(size = 16),
axis.text.y = ggtext::element_markdown())
对于绘图最左侧的真正 fixed-width 文本区域,您可以使用 annotation_custom
p1 +
annotation_custom(grid::rectGrob(x = unit(10, "mm"), y = 0.5,
width = unit(20, "mm"), height = 1,
gp = grid::gpar(col = NA))) +
annotation_custom(grid::textGrob(df.labels$Labels,
x = unit(10, "mm"),
y = c(0.81, 0.5, 0.19)))