估计 ggplot2 中图例占用的地块百分比
Estimate percentage of plot taken up by legend in ggplot2
我有一些 ggplot 功能,但我想给用户一个警告,以防他们滥用它。问题是这样的:如果有很多组并且组名很长,图例就会变得很大,占据整个情节:
但如果我要更改地块名称,我会得到:
我有的是:
- ggplot / ggbuild 对象
- 图的尺寸window(默认为 480 x 320)但可以更改。
我想用这些来估计图例占用的总面积(这样如果图例大小/绘图大小的比率太大,我可以发出警告)。这是我用来创建图形的一些示例代码:
library(ggplot2)
# stolen from https://ryouready.wordpress.com/2008/12/18/generate-random-string-name/
MHmakeRandomString <- function(n=1, lenght=12) {
randomString <- c(1:n)
for (i in 1:n)
{
randomString[i] <- paste(sample(c(0:9, letters, LETTERS),
lenght, replace=TRUE),
collapse="")
}
return(randomString)
}
makeData <- function(k, useLongNames = FALSE) {
x <- c(1, 100)
X <- cbind(1, x)
b <- matrix(rnorm(2*k), k, 2)
y <- numeric(2*k)
for (i in seq_len(k))
y[1:2 + 2*(i-1)] <- X %*% b[i, ]
df <- data.frame(x = c(1, n), y = y)
if (useLongNames) {
df$g <- factor(rep(MHmakeRandomString(k), each = 2))
} else {
df$g <- factor(rep(1:k, each = 2))
}
return(df)
}
# okayish plot
df <- makeData(50)
g0 <- ggplot(data = df, aes(x = x, y = y, group = g, color = g)) +
geom_line() +
guides(color=guide_legend(nrow=5))
# unreadable plot
df <- makeData(50, useLongNames = TRUE)
g1 <- ggplot(data = df, aes(x = x, y = y, group = g, color = g)) +
geom_line() +
guides(color=guide_legend(nrow=5))
# to plot
# x11(width = 480, height = 320)
# print(g0)
# x11(width = 480, height = 320)
# print(g1)
我认为答案在 ggplotGrob()
中的某处。但是,我不熟悉 grobs(并且找不到明确的文档)并且被困在
gGrob0 <- ggplotGrob(g0)
gGrob1 <- ggplotGrob(g1)
gGrob0$grobs[[15]]$grobs[[1]]$grobs # all legend elements
convertWidth(grobWidth(gGrob0$grobs[[15]]), unitTo = "inches") # 4.5128 inches
convertWidth(grobWidth(gGrob1$grobs[[15]]), unitTo = "inches") # 12.419 inches
# but this is not correct:
# number of legend columns x legend width <= plot width
# 10 * 12.419 <= 480
这似乎给了我很多关于我感兴趣的东西的信息。我如何将这些信息转换成图例将占用的总宽度?非常感谢。
这是我的解决方案(灵感来自 m-dz 的评论)。对象 g0
和 g1
来自问题中的代码。
plotAndPrintRatio <- function(g, width, height) {
gGrob <- ggplotGrob(g)
tmpfile <- tempfile(pattern = "png")
png(tmpfile, width = width, height = height) # it is necessary to open a device
plot(g)
legendSize <- as.numeric(convertWidth(grobWidth(gGrob$grobs[[15]]), unitTo = "inches"))
plotSize <- as.numeric(convertWidth(grobWidth(gGrob$grobs[[7]]), unitTo = "inches"))
print(legendSize / plotSize) # the ratio of legend size to plot size
dev.off()
return(tmpfile)
}
# problem only in the first plot
f1 <- plotAndPrintRatio(g0, width = 480, height = 320) # 0.6769345
f2 <- plotAndPrintRatio(g1, width = 480, height = 320) # 1.887872 --> too big!
# larger window size fixes the problem
f3 <- plotAndPrintRatio(g0, width = 1200, height = 900) # 0.2707738
f4 <- plotAndPrintRatio(g1, width = 1200, height = 900) # 0.7551488
filesList <- list(f1, f2, f3, f4)
# to show the saved pngs:
dev.off() # might be needed to clean up the plotting window
grid::grid.raster(png::readPNG(f1))
grid::grid.raster(png::readPNG(f2))
grid::grid.raster(png::readPNG(f3))
grid::grid.raster(png::readPNG(f4))
# to remove the tempfiles created:
# lapply(filesList, file.remove)
我有一些 ggplot 功能,但我想给用户一个警告,以防他们滥用它。问题是这样的:如果有很多组并且组名很长,图例就会变得很大,占据整个情节:
但如果我要更改地块名称,我会得到:
我有的是:
- ggplot / ggbuild 对象
- 图的尺寸window(默认为 480 x 320)但可以更改。
我想用这些来估计图例占用的总面积(这样如果图例大小/绘图大小的比率太大,我可以发出警告)。这是我用来创建图形的一些示例代码:
library(ggplot2)
# stolen from https://ryouready.wordpress.com/2008/12/18/generate-random-string-name/
MHmakeRandomString <- function(n=1, lenght=12) {
randomString <- c(1:n)
for (i in 1:n)
{
randomString[i] <- paste(sample(c(0:9, letters, LETTERS),
lenght, replace=TRUE),
collapse="")
}
return(randomString)
}
makeData <- function(k, useLongNames = FALSE) {
x <- c(1, 100)
X <- cbind(1, x)
b <- matrix(rnorm(2*k), k, 2)
y <- numeric(2*k)
for (i in seq_len(k))
y[1:2 + 2*(i-1)] <- X %*% b[i, ]
df <- data.frame(x = c(1, n), y = y)
if (useLongNames) {
df$g <- factor(rep(MHmakeRandomString(k), each = 2))
} else {
df$g <- factor(rep(1:k, each = 2))
}
return(df)
}
# okayish plot
df <- makeData(50)
g0 <- ggplot(data = df, aes(x = x, y = y, group = g, color = g)) +
geom_line() +
guides(color=guide_legend(nrow=5))
# unreadable plot
df <- makeData(50, useLongNames = TRUE)
g1 <- ggplot(data = df, aes(x = x, y = y, group = g, color = g)) +
geom_line() +
guides(color=guide_legend(nrow=5))
# to plot
# x11(width = 480, height = 320)
# print(g0)
# x11(width = 480, height = 320)
# print(g1)
我认为答案在 ggplotGrob()
中的某处。但是,我不熟悉 grobs(并且找不到明确的文档)并且被困在
gGrob0 <- ggplotGrob(g0)
gGrob1 <- ggplotGrob(g1)
gGrob0$grobs[[15]]$grobs[[1]]$grobs # all legend elements
convertWidth(grobWidth(gGrob0$grobs[[15]]), unitTo = "inches") # 4.5128 inches
convertWidth(grobWidth(gGrob1$grobs[[15]]), unitTo = "inches") # 12.419 inches
# but this is not correct:
# number of legend columns x legend width <= plot width
# 10 * 12.419 <= 480
这似乎给了我很多关于我感兴趣的东西的信息。我如何将这些信息转换成图例将占用的总宽度?非常感谢。
这是我的解决方案(灵感来自 m-dz 的评论)。对象 g0
和 g1
来自问题中的代码。
plotAndPrintRatio <- function(g, width, height) {
gGrob <- ggplotGrob(g)
tmpfile <- tempfile(pattern = "png")
png(tmpfile, width = width, height = height) # it is necessary to open a device
plot(g)
legendSize <- as.numeric(convertWidth(grobWidth(gGrob$grobs[[15]]), unitTo = "inches"))
plotSize <- as.numeric(convertWidth(grobWidth(gGrob$grobs[[7]]), unitTo = "inches"))
print(legendSize / plotSize) # the ratio of legend size to plot size
dev.off()
return(tmpfile)
}
# problem only in the first plot
f1 <- plotAndPrintRatio(g0, width = 480, height = 320) # 0.6769345
f2 <- plotAndPrintRatio(g1, width = 480, height = 320) # 1.887872 --> too big!
# larger window size fixes the problem
f3 <- plotAndPrintRatio(g0, width = 1200, height = 900) # 0.2707738
f4 <- plotAndPrintRatio(g1, width = 1200, height = 900) # 0.7551488
filesList <- list(f1, f2, f3, f4)
# to show the saved pngs:
dev.off() # might be needed to clean up the plotting window
grid::grid.raster(png::readPNG(f1))
grid::grid.raster(png::readPNG(f2))
grid::grid.raster(png::readPNG(f3))
grid::grid.raster(png::readPNG(f4))
# to remove the tempfiles created:
# lapply(filesList, file.remove)