【问题标题】:ggplot2 two-line label with expressionggplot2 带有表达式的两行标签
【发布时间】:2012-10-24 19:13:42
【问题描述】:

我想用expression() 语句在两行上写一个轴标签。但是,plotmathexpression 不允许这样做(例如,下标文本出现在最右侧)。我发现this discussion circa 2005 有一个类似的问题,但是他们提供的解决方法并没有转化为我在 ggplot2 中的应用程序。 A recent question 解决了多行表达式语句的不同排列,但再次提供的解决方法不适用于此处。

例子:

p <- ggplot(mtcars,aes(x=wt,y=mpg))+
  geom_point()+
  xlab(expression(paste("A long string of text goes here just for the purpose \n of illustrating my point Weight "[reported])))
try(ggsave(plot=p,filename=<some file>,height=4,width=6))

产生一个图像,当我希望它位于前一个单词旁边时,下标“reported”被踢到右边。

【问题讨论】:

  • 为什么这里需要一个表达式(即 plotmath)?如果只是一个强项,则在字符向量中弹出一个\n
  • 也许我不明白你的建议,但我确实在标签中包含了 \n。我需要表达才能在我的应用程序中使用某些符号(例如下标和度数)。
  • 对,你的例子不需要表达式(),简单的粘贴()就可以了。请参阅 ?plotmath 中的 atop() 运算符

标签: r ggplot2


【解决方案1】:

ggtext 包提供了一个不同的选项,允许 HTML 标签格式化/自定义标签和文本。

library(ggtext)
ggplot(mtcars, aes(wt, mpg)) +
  geom_point() +
  xlab("A long string of text goes here just for the purpose<br>of illustrating my point Weight<sub>reported</sub>") +
  theme(axis.title.x = element_markdown())

【讨论】:

  • +1 我对此进行了调整,以使用theme(axis.text.x = element_markdown())制作多行斜体条形图标签
【解决方案2】:

1) 使用cowplot::draw_label() 的解决方案

也可以使用cowplot 包中的注释函数draw_label()(在this 讨论中建议)。我们可以调用cowplot::draw_label() 尽可能多的文本行。当cowplot::draw_label()cowplot::ggdraw()结合使用时,它可以在canvas/sheet上的任意位置进行注释,坐标范围为0到1(相对于整个canvas)。

需要调整注释位置并为自定义轴标题留出足够的空间。

请注意,cowplot 包当前更改了默认的 ggplot 主题,因此,如果需要,请在加载包后使用 theme_set(),如 here 所述。

还要注意,函数 cowplot::draw_label() 在底层使用 ggplot2::annotation_custom()。我将在下面的第二部分中详细介绍这一点。

library(ggplot2)
library(cowplot)
#> 
#> Attaching package: 'cowplot'
#> The following object is masked from 'package:ggplot2':
#> 
#>     ggsave

# If needed, revert to default theme (cowplot modifies the theme); 
# theme_set(theme_grey())

p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
# Make enough space for the custom two lines axis title
p <- p + 
  xlab("") + # empty label
  # Tweak the margins (push the label down by forcing a wider top margin)
  theme(axis.title.x = element_text(size = 10, # also adjust text size if needed
                                    margin = margin(t = 10, r = 0, b = 0, l = 0,
                                                    unit = "mm")))

# The two lines we wish on the plot
line_1 <- "A long string of text for the purpose"
line_2 <- expression(paste("of illustrating my point" [reported]))
# Or avoid paste() (is not actually needed)
# line_2 <- expression("of illustrating my point" [reported])

# Call cowplot::draw_label two times to plot two lines of text
ggdraw(p) + 
  draw_label(line_1, x = 0.55, y = 0.075) + # use relative coordinates for positioning
  draw_label(line_2, x = 0.55, y = 0.025)

请注意,cowplot::draw_label() 也可以与设置裁剪关闭结合使用,coord_cartesian(clip = "off"),它允许在画布上的任何位置进行绘图。这次我们不再使用相对坐标,而是使用绘图/数据中的坐标(绝对坐标):

# Other two expressions
line_1b <- expression(bolditalic('First line'))
line_2b <- expression(integral(f(x)*dx, a, b))

p + coord_cartesian(clip = "off") + # allows plotting anywhere on the canvas
  draw_label(line_1b, x = 3.5, y = 8.2) + # use absolute coordinates for positioning
  draw_label(line_2b, x = 3.5, y = 6)

reprex package (v0.2.1) 于 2019 年 1 月 14 日创建


2) 使用ggplot2::annotation_custom() 的解决方案

如前所述,cowplot::draw_label()ggplot2::annotation_custom() 的包装器。因此,我们可以直接使用ggplot2::annotation_custom() 来代替cowplot::draw_label(),并结合设置剪裁-coord_cartesian(clip = "off"),这可以通过合并this pull request 来实现。

但是,这种方法更冗长,有更多的坐标参数,我们需要使用grid::textGrob()

# Some other two lines we wish on the plot as OX axis title
line_1c <- expression("Various fonts:" ~ bolditalic("bolditalic") ~ bold("bold") ~ italic("italic"))
line_2c <- expression("this" ~~ sqrt(x, y) ~~ "or this" ~~ sum(x[i], i==1, n) ~~ "math expression")
# the ~~ ads a bit more space than ~ between the expression's components

p + coord_cartesian(clip = "off") +
  annotation_custom(grid::textGrob(line_1c), xmin = 3.5, xmax = 3.5, ymin = 7.3, ymax = 7.3) +
  annotation_custom(grid::textGrob(line_2c), xmin = 3.5, xmax = 3.5, ymin = 5.5, ymax = 5.5)

reprex package (v0.2.1) 于 2019 年 1 月 14 日创建

【讨论】:

    【解决方案3】:

    你可以使用这个技巧,

    library(gridExtra)
    library(grid)
    
    element_custom <- function() {
      structure(list(), class = c("element_custom", "element_text"))
    }
    
    element_grob.element_custom <- function(element, label="", ...)  {
    
      mytheme <- ttheme_minimal(core = list(fg_params = list(parse=TRUE, 
                                                             hjust=0, x=0.1)))
      disect <- strsplit(label, "\\n")[[1]]
      tableGrob(as.matrix(disect), theme=mytheme)
    }
    
    # default method is unreliable
    heightDetails.gtable <- function(x) sum(x$heights)
    
    ggplot(iris, aes(Sepal.Length, Sepal.Width)) +
      geom_line() + 
      labs(x= "First~line \n italic('and a second') \n integral(f(x)*dx, a, b)")+
      (theme_grey() %+replace% theme(axis.title.x = element_custom()))
    

    【讨论】:

    • 现在对我来说非常有用......但不值得使用 R 3.4.0 和 ggplot2_2.2.1 :(
    【解决方案4】:

    我认为这是一个错误。 (或者是“不支持多行表达式”这一事实的结果,如您链接到的对话中所述)。

    Gavin Simpson 提到的解决方法是:

    #For convenience redefine p as the unlabeled plot
    p <- ggplot(mtcars,aes(x=wt,y=mpg))+geom_point()
    
    #Use atop to fake a line break
    p + xlab(expression(atop("A long string of text for the purpose", paste("of illustrating my point" [reported]))))
    

    可以使用带下标的真正换行符。在下面的简短示例中,与您的示例具有相同的形式,下标正确地放置在与文本的其余部分相邻的位置,但两行文本没有正确居中:

    p + xlab(expression(paste("line1 \n line2 a" [b])))
    

    我认为在这两种情况下,当上一行文本比下一行文本长时,下标放置错误。比较

    p + xlab(expression(paste("abc \n abcd" [reported])))
    

    p + xlab(expression(paste("abc \n ab" [reported])))
    

    下标总是与上线右端的右侧对齐。

    p + xlab(expression(paste("abcdefghijklmnop \n ab" [reported])))
    

    【讨论】:

    • 很好的演示。不确定如何处理下标,但第二行的 start 略微向右移动的原因是换行符后有一个额外的空格。输入 p+xlab(expression(paste("abcdefghijklmnop \nab" [reported]))) 而不是 p+xlab(expression(paste("abcdefghijklmnop \n ab" [reported]))) 至少确保两行 start 在同一个位置...虽然这不能绕过下标之前难看的间隙。
    猜你喜欢
    • 2015-12-16
    • 1970-01-01
    • 1970-01-01
    • 2016-12-02
    • 2014-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多