R:ggtext包丰富ggplot2中文本的表现力

2020-12-03 15:58:11 浏览数 (1)

ggtext让ggplot2图像也可以使用html、markdown及css语法,丰富了ggplot2文本的表现力。

在主题部分如坐标轴标题、坐标轴标签、图形标题、副标题、脚注等,可以使用html、markdown及css语法的文本,然后在theme函数中使用element_markdown和element_textbox进行渲染即可。

在panel区域,也就是类似于原生的geom_text或者geom_label的图层所作用的区域,可以使用geom_richtext或者geom_textbox来扩展文本标注的表现力。

element_markdown

element_markdown可以渲染html、markdown及css语法,获得高级的文本表现。

下图中可以看到,y轴标签使用了html的标记和css语法,改变文字为倾斜和不同颜色。脚注基本上是markdown语法,加了一个html换行标签。

代码语言:javascript复制
data <- tibble(
  bactname = c("Staphylococcaceae", "Moraxella", "Streptococcus", "Acinetobacter"),
  OTUname = c("OTU 1", "OTU 2", "OTU 3", "OTU 4"),
  value = c(-0.5, 0.5, 2, 3)
)

data %>% mutate(
  color = c("#009E73", "#D55E00", "#0072B2", "#000000"),
  name = glue("<i style='color:{color}'>{bactname}</i> ({OTUname})"),
  name = fct_reorder(name, value)
)  %>%
  ggplot(aes(value, name, fill = color))   
  geom_col(alpha = 0.5)   
  scale_fill_identity()  
  labs(caption = "Example posted on **stackoverflow.com**<br>(using made-up data)")  
  theme(
    axis.text.y = element_markdown(),
    plot.caption = element_markdown(lineheight = 1.2)
  )

html的img标签其实也是支持的,但是目前貌似出现了bug,无法出图。正常情况下应该如下图所示:

代码语言:javascript复制
labels <- c(
  setosa = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/8/86/Iris_setosa.JPG/180px-Iris_setosa.JPG'
    width='100' /><br>*I. setosa*",
  virginica = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/3/38/Iris_virginica_-_NRCS.jpg/320px-Iris_virginica_-_NRCS.jpg'
    width='100' /><br>*I. virginica*",
  versicolor = "<img src='https://upload.wikimedia.org/wikipedia/commons/thumb/2/27/20140427Iris_versicolor1.jpg/320px-20140427Iris_versicolor1.jpg'
    width='100' /><br>*I. versicolor*"
)

ggplot(iris, aes(Species, Sepal.Width))  
  geom_boxplot()  
  scale_x_discrete(
    name = NULL,
    labels = labels
  )  
  theme(
    axis.text.x = element_markdown(color = "black", size = 11)
  )

element_textbox

element_textbox可以让长文本自动折叠,但是它在轴标签上无法使用。文本的旋转角度也不能是任意的,只能是0、90、180、270。

一般情况下不使用element_textbox,而是使用element_textbox_simple,它和element_textbox是一样的,只不过更加容易使用,很多默认参数都已经设置好了。

代码语言:javascript复制
ggplot(mtcars, aes(disp, mpg))   
  geom_point()  
  labs(
    title = "<b>Fuel economy vs. engine displacement</b><br>
    <span style = 'font-size:10pt'>Lorem ipsum *dolor sit amet,*
    consectetur adipiscing elit, **sed do eiusmod tempor incididunt** ut
    labore et dolore magna aliqua. <span style = 'color:red;'>Ut enim
    ad minim veniam,</span> quis nostrud exercitation ullamco laboris nisi
    ut aliquip ex ea commodo consequat.</span>",
    x = "displacement (in<sup>3</sup>)",
    y = "Miles per gallon (mpg)<br><span style = 'font-size:8pt'>A measure of
    the car's fuel efficiency.</span>"
  )  
  theme(
    plot.title.position = "plot",
    plot.title = element_textbox_simple(
      size = 13,
      lineheight = 1,
      padding = margin(5.5, 5.5, 5.5, 5.5),
      margin = margin(0, 0, 5.5, 0),
      fill = "cornsilk"
    ),
    axis.title.x = element_textbox_simple(
      width = NULL,
      padding = margin(4, 4, 4, 4),
      margin = margin(4, 0, 0, 0),
      linetype = 1,
      r = grid::unit(8, "pt"),
      fill = "azure1"
    ),
    axis.title.y = element_textbox_simple(
      hjust = 0,
      orientation = "left-rotated",
      minwidth = unit(1, "in"),
      maxwidth = unit(2, "in"),
      padding = margin(4, 4, 2, 4),
      margin = margin(0, 0, 2, 0),
      fill = "lightsteelblue1"
    )
  )

element_box在使用上非常有意思的一个地方是可以修改分面图的strip格式,如下图所示。

代码语言:javascript复制
ggplot(mpg, aes(cty, hwy))   
  geom_point()  
  facet_wrap(~class)  
  cowplot::theme_half_open(12)  
  cowplot::background_grid()  
  theme(
    strip.background = element_blank(),
    strip.text = element_textbox(
      size = 12,
      color = "white", fill = "#5D729D", box.color = "#4A618C",
      halign = 0.5, linetype = 1, r = unit(5, "pt"), width = unit(1, "npc"),
      padding = margin(2, 0, 1, 0), margin = margin(3, 3, 3, 3)
    )
  )

上图是固定的格式显示,strip的格式都是一样的,其实也可以更进一步,将strip按照分组显示,从而实现多一个维度的信息展示,比如此图的stipe文本是class信息(因为这里的分面是facet_wrap(~class)控制的),那么可以将原始的数据的class格式化为一个html的标记,下图就是将strip的字体颜色映射为mpg中的cyl变量,当然了由于class中存在多种cyl信息,因此被拆分成了多个子图,这也是正常情况。如果要和以前一样的子图数量,其实可以按照class的水平值,各自组合一个颜色即可。

代码语言:javascript复制
mpg %>% mutate(cyl = fct_recode(factor(cyl),
                                red = "4",
                                blue = "5", 
                                yellow = "6",
                                green = "8")) %>%
  mutate(class = str_glue("<span style = 'color:{cyl}'>{class}</span>")) %>%
  ggplot(aes(cty, hwy))   
    geom_point()  
    facet_wrap(~class)  
    cowplot::theme_half_open(12)  
    cowplot::background_grid()  
    theme(
      strip.background = element_blank(),
      strip.text = element_textbox(
        size = 12,
        color = "white", fill = "#5D729D", box.color = "#4A618C",
        halign = 0.5, linetype = 1, r = unit(5, "pt"), width = unit(1, "npc"),
        padding = margin(2, 0, 1, 0), margin = margin(3, 3, 3, 3)
      )
    )

geom_richtext

geom_richtext和基础图层geom_text或者geom_label类似,但是扩增了很多格式控制。

代码语言:javascript复制
df <- tibble(
  label = c(
    "Some text **in bold.**",
    "Linebreaks<br>Linebreaks<br>Linebreaks",
    "*x*<sup>2</sup>   5*x*   *C*<sub>*i*</sub>",
    "Some <span style='color:blue'>blue text **in bold.**</span><br>And *italics text.*<br>
    And some <span style='font-size:18pt; color:black'>large</span> text."
  ),
  x = c(.2, .1, .5, .9),
  y = c(.8, .4, .1, .5),
  hjust = c(0.5, 0, 0, 1),
  vjust = c(0.5, 1, 0, 0.5),
  angle = c(0, 0, 45, -45),
  color = c("black", "blue", "black", "red"),
  fill = c("cornsilk", "white", "lightblue1", "white")
)


ggplot(df)  
  aes(
    x, y, label = label, angle = angle, color = color, fill = fill,
    hjust = hjust, vjust = vjust
  )  
  geom_richtext()  
  geom_point(color = "black", size = 2)  
  scale_color_identity()  
  scale_fill_identity()  
  xlim(0, 1)   ylim(0, 1)

geom_textbox

不同于geom_richtext,geom_textbox可以自动折叠文本,也就是说不需要手动换行(br标签)。它和element_textbox类似,也无法旋转任意角度。

代码语言:javascript复制
df <- tibble(
  label = rep("Lorem ipsum dolor **sit amet,** consectetur adipiscing elit,
    sed do *eiusmod tempor incididunt* ut labore et dolore magna
    aliqua.", 2),
  x = c(0, .6),
  y = c(1, .6),
  hjust = c(0, 0),
  vjust = c(1, 0),
  orientation = c("upright", "right-rotated"),
  color = c("black", "blue"),
  fill = c("cornsilk", "white") )


ggplot(df)  
  aes(
    x, y, label = label, color = color, fill = fill,
    hjust = hjust, vjust = vjust,
    orientation = orientation
  )  
  geom_textbox(width = unit(0.4, "npc"))  
  geom_point(color = "black", size = 2)  
  scale_discrete_identity(aesthetics = c("color", "fill", "orientation"))  
  xlim(0, 1)   ylim(0, 1)

0 人点赞