我正在寻找一种在facet_wrapfacet_grid调用中动态包装条标签文本的方法.我已经找到了一种使用strwrap来实现这一点的方法,但我需要指定一个width,以使输出按预期工作.通常,刻面的数量事先不知道,因此这种方法需要我根据数据集和绘图大小反复调整width参数.是否可以动态指定包裹功能的宽度,或者是否有另一种方法可以更好地标记镶嵌面?

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))

推荐答案

多亏了@baptiste和@thunk的指导,我创建了下面的函数,它似乎在自动包装刻面标签方面做得相当好.不过,改进建议总是受欢迎的.

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)

R相关问答推荐

在之前合并的数据.tables中分配新列后.internal.selfref无效

计算转换的次数

逐行替代引用前一行的for循环

基于2行删除重复项指定每列要执行的操作

R gtsummary tBL_summary,包含分层和两个独立分组变量

次级y轴R gggplot2

获取列中值更改的行号

如何编辑ggplot的图例字使用自定义对象(gtable)?'

ggplot的轴标签保存在officer中时被剪切

如何根据R中其他列的值有条件地从列中提取数据?

从BRM预测价值

`lazy_dt`不支持`dplyr/across`?

绘制采样开始和采样结束之间的事件

更新R中的数据表(使用data.table)

将向量元素重新排序为R中的第二个

如何在PDF格式的kableExtra表格中显示管道字符?

优化从每个面的栅格中提取值

使用列中的值来调用函数调用中应使用的其他列

将文本批注减少到gglot的y轴上的单个值

按组使用dummy r获取高于标准的行的平均值