我正在寻找一种在facet_wrap
或facet_grid
调用中动态包装条带标签文本的方法。我已经找到了一种使用strwrap
来完成此任务的方法,但是我需要指定一个width
才能使输出按预期方式工作。通常,面的数量事先是未知的,因此此方法要求我根据数据集和绘图大小迭代地调整width
参数。是否可以动态指定wrap函数的宽度,或者是否有另一种更好的方法来标记facet?
library(ggplot2)
df = expand.grid(group=paste(c("Very Very Very Long Group Name "), 1:9),
x=rnorm(5), y=rnorm(5), stringsAsFactors=FALSE)
df$groupwrap = unlist(lapply(strwrap(df$group, width=30, simplify=FALSE), paste,
collapse="\n"))
p = ggplot(df) +
geom_point(aes(x=x, y=y)) +
facet_wrap(~groupwrap)
更新:基于@baptiste和@thunk提供的指导,我提出了下面的选择。目前,它只适用于指定的字体系列和大小,但理想情况下,还应该能够使用默认的theme
设置。也许有更多ggplot2
经验的人会有一些改进的建议。
library('grid')
grobs <- ggplotGrob(p)
sum = sum(sapply(grobs$width, function(x) convertWidth(x, "in")))
panels_width = par("din")[1] - sum # inches
df$group = as.factor(df$group)
npanels = nlevels(df$group)
if (class(p$facet)[1] == "wrap") {
cols = n2mfrow(npanels)[1]
} else {
cols = npanels
}
ps = 12
family = "sans"
pad = 0.01 # inches
panel_width = panels_width / cols
char_width = strwidth(levels(df$group)[
which.max(nchar(levels(df$group)))], units="inches", cex=ps / par("ps"),
family=family) / max(nchar(levels(df$group)))
width = floor((panel_width - pad)/ char_width) # characters
df$groupwrap = unlist(lapply(strwrap(df$group, width=width, simplify=FALSE),
paste, collapse="\n"))
ggplot(df) +
geom_point(aes(x=x, y=y)) +
facet_wrap(~groupwrap) +
theme(strip.text.x=element_text(size=ps, family=family))
发布于 2013-05-24 21:11:59
感谢@baptiste和@thunk的指导,我创建了下面的函数,它似乎在自动包装facet标签方面做得很好。不过,改进的建议总是受欢迎的。
strwrap_strip_text = function(p, pad=0.05) {
# get facet font attributes
th = theme_get()
if (length(p$theme) > 0L)
th = th + p$theme
require("grid")
grobs <- ggplotGrob(p)
# wrap strip x text
if ((class(p$facet)[1] == "grid" && !is.null(names(p$facet$cols))) ||
class(p$facet)[1] == "wrap")
{
ps = calc_element("strip.text.x", th)[["size"]]
family = calc_element("strip.text.x", th)[["family"]]
face = calc_element("strip.text.x", th)[["face"]]
if (class(p$facet)[1] == "wrap") {
nm = names(p$facet$facets)
} else {
nm = names(p$facet$cols)
}
# get number of facet columns
levs = levels(factor(p$data[[nm]]))
npanels = length(levs)
if (class(p$facet)[1] == "wrap") {
cols = n2mfrow(npanels)[1]
} else {
cols = npanels
}
# get plot width
sum = sum(sapply(grobs$width, function(x) convertWidth(x, "in")))
panels_width = par("din")[1] - sum # inches
# determine strwrap width
panel_width = panels_width / cols
mx_ind = which.max(nchar(levs))
char_width = strwidth(levs[mx_ind], units="inches", cex=ps / par("ps"),
family=family, font=gpar(fontface=face)$font) /
nchar(levs[mx_ind])
width = floor((panel_width - pad)/ char_width) # characters
# wrap facet text
p$data[[nm]] = unlist(lapply(strwrap(p$data[[nm]], width=width,
simplify=FALSE), paste, collapse="\n"))
}
if (class(p$facet)[1] == "grid" && !is.null(names(p$facet$rows))) {
ps = calc_element("strip.text.y", th)[["size"]]
family = calc_element("strip.text.y", th)[["family"]]
face = calc_element("strip.text.y", th)[["face"]]
nm = names(p$facet$rows)
# get number of facet columns
levs = levels(factor(p$data[[nm]]))
rows = length(levs)
# get plot height
sum = sum(sapply(grobs$height, function(x) convertWidth(x, "in")))
panels_height = par("din")[2] - sum # inches
# determine strwrap width
panels_height = panels_height / rows
mx_ind = which.max(nchar(levs))
char_height = strwidth(levs[mx_ind], units="inches", cex=ps / par("ps"),
family=family, font=gpar(fontface=face)$font) /
nchar(levs[mx_ind])
width = floor((panels_height - pad)/ char_height) # characters
# wrap facet text
p$data[[nm]] = unlist(lapply(strwrap(p$data[[nm]], width=width,
simplify=FALSE), paste, collapse="\n"))
}
invisible(p)
}
要使用该函数,请调用它来代替print
。
library(ggplot2)
df = expand.grid(group=paste(c("Very Very Very Long Group Name "), 1:4),
group1=paste(c("Very Very Very Long Group Name "), 5:8),
x=rnorm(5), y=rnorm(5), stringsAsFactors=FALSE)
p = ggplot(df) +
geom_point(aes(x=x, y=y)) +
facet_grid(group1~group)
strwrap_strip_text(p)
发布于 2016-11-16 10:44:29
自从这个问题发布后,带有ggplot2
的新label_wrap_gen()
函数(我认为是>= 1.0.0 )很好地处理了这个问题:
facet_wrap(~groupwrap, labeller = labeller(groupwrap = label_wrap_gen(10)))
请注意,您必须指定宽度才能使其工作。
对于较旧的ggplot2版本:
facet_wrap(~groupwrap, labeller = label_wrap_gen())
发布于 2013-05-21 05:51:06
(作为评论太长了,但也不是真正的答案)
我不认为一般的解决方案会直接存在于ggplot2中;这是网格单元自引用的经典问题:ggplot2想要动态计算视口大小,而strwrap需要知道固定的宽度来决定如何拆分文本。(有一个非常相似的问题,但我忘记了时间和地点)。
但是,您可以编写一个帮助函数来估计在绘制之前需要多少包装。在伪代码中,
# takes the facetting variable and device size
estimate_wrap = function(f, size=8, fudge=1){
n = nlevels(f)
for (loop over the labels of strwidth wider than (full.size * fudge) / n){
new_factor_level[ii] = strwrap(label[ii], available width)
}
return(new_factor)
}
(需要一些标准单位转换)
当然,如果你想使用space="free"
,事情会变得更复杂。
https://stackoverflow.com/questions/16654691
复制相似问题