ggplot geom_point:如何设置自定义绘图符号的字体?

11

使用ggplot::geom_point,我们可以使用scale_shape_manual设置任何字符作为绘图符号。我举个例子来说明这个目的:使用三角形在每个单元格中显示两个值,制作一个热度图:

require(ggplot2)

data <- data.frame(
    val = rnorm(40),
    grp = c(rep('a', 20), rep('b', 20)),
    x   = rep(letters[1:4], 5),
    y   = rep(letters[1:5], 4)
)

p <- ggplot(data, aes(x = x, y = y, color = val, shape = grp)) +
    geom_point(size = 18) +
    scale_shape_manual(values=c("\u25E4","\u25E2")) +
    theme_minimal() +
    theme(panel.grid = element_blank())

ggsave('triangle-tiles.pdf', device = cairo_pdf, width = 4.1, height = 3.5)

具有geom_point的三角形热力图

如果用于符号的字体没有这些特殊字符,那么此方法将无法正常工作。否则,显式定义字体并使用 geom_text 可以得到相同的结果:

require(dplyr)

data <- data %>% mutate(sym = ifelse(grp == 'a', "\u25E4", "\u25E2"))

p <- ggplot(data, aes(x = x, y = y, color = val, label = sym)) +
    geom_text(size = 18, family = 'DejaVu Sans') +
    theme_minimal() +
    theme(
        panel.grid = element_blank()
    )

ggsave('triangle-tiles-2.pdf', device = cairo_pdf, width = 4.1, height = 3.5)

然而,事实上,在geom_point中同样使用来自字体的字符,这让我非常好奇如何覆盖默认设置。

我检查了此绘图的grob,试图按照这个示例的方法进行操作,并发现点是这样的:

gr <- ggplotGrob(p)
gr[['grobs']][[6]]$children$geom_point

这里有 x, y, size, lwd(如上例所示)等,但没有字体。我也想知道如何直接自动地从根 grob 找到点的 grob,例如使用 grid::getGrob,在引用的示例中,grid::grid.edit 找到了它们。

我在这里找到了一些有希望的代码,其中使用了 editGtable,但我没有在任何包中找到这个方法,可能是一个旧方法。然后我尝试了 editGrob,但没有成功:

font <- gpar(fontfamily = 'DejaVu Sans', fontsize = 14)
editGrob(gr[['grobs']][[6]], 'geom_point.points', grep = TRUE, global = TRUE, gp = font)

主题(文本=element_text(family="DejaVu Sans")) - eipi10
谢谢@eipi10,我已经尝试过了,但它并没有影响绘图符号,只有刻度标签、标题等。 - deeenes
1
我认为这两个问题非常相关:https://dev59.com/gVQJ5IYBdhLWcg3w35-R 和 https://dev59.com/pnM_5IYBdhLWcg3wZSPX。这可能是“设备的适当字体”,您可以在调用设备时使用family进行设置。对于ggsave,您只需添加字体系列`family = ...`即可。不幸的是,我目前正在我的Mac上与Unicode字符作斗争(类似于此处https://dev59.com/qGcs5IYBdhLWcg3wiEiK),因此我无法发布漂亮的示例图像。 - tjebo
1个回答

3
以下是一种有点技巧性的方法,但您可以将一个点图层包装在一个新的类中,该类将字体系列分配给点的图形参数。在下面的示例中,新类调用绘制图层和关键字中点的父方法,然后将字体系列分配给图形参数。
require(ggplot2)
#> Loading required package: ggplot2

point_with_family <- function(layer, family) {
  old_geom <- layer$geom
  new_geom <- ggproto(
    NULL, old_geom,
    draw_panel = function(self, data, panel_params, coord, na.rm = FALSE) {
      pts <- ggproto_parent(GeomPoint, self)$draw_panel(
        data, panel_params, coord, na.rm = na.rm
      )
      pts$gp$fontfamily <- family
      pts
    },
    draw_key = function(self, data, params, size) {
      pts <- ggproto_parent(GeomPoint, self)$draw_key(
        data, params, size
      )
      pts$gp$fontfamily <- family
      pts
    }
  )
  layer$geom <- new_geom
  layer
}

data <- data.frame(
  val = rnorm(40),
  grp = c(rep('a', 20), rep('b', 20)),
  x   = rep(letters[1:4], 5),
  y   = rep(letters[1:5], 4)
)

p <- ggplot(data, aes(x = x, y = y, color = val, shape = grp)) +
  point_with_family(geom_point(size = 18), "DejaVu Sans") +
  scale_shape_manual(values=c("\u25E4","\u25E2")) +
  theme_minimal() +
  theme(panel.grid = element_blank())

ggsave('triangle-tiles-2.pdf', plot = p, device = cairo_pdf, width = 4.1, height = 3.5)

本文创建于2021年8月29日,使用reprex包(v2.0.0)

在此输入图片描述

如果字体不支持Unicode字符:

在此输入图片描述


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接