【问题标题】:Apply bold font on specific axis ticks在特定轴刻度上应用粗体字
【发布时间】:2020-05-11 15:24:52
【问题描述】:

这是一个情节:

library(ggplot2)
library(tibble)

ggplot(head(mtcars) %>% rownames_to_column("cars"),
       aes(x = reorder(cars, - drat), 
           y = drat)) +
  geom_col() +
  coord_flip()

如何在特定汽车名称上应用粗体字(例如,仅在“Hornet 4 Drive”和“Datsun 710”上)?

我更喜欢一个非常“通用”的答案,即一个可以轻松应用特定颜色或其他字体系列而不是粗体字体的答案。

【问题讨论】:

    标签: r ggplot2


    【解决方案1】:

    ggtext 允许您对轴标签和其他文本使用 markdown 和 html 标签。所以我们可以创建一个函数来传递给scale_y_discretelabels 参数(正如@RomanLuštrik 在他们的评论中所建议的那样),通过它我们可以选择要突出显示的标签、颜色和字体系列:

    library(tidyverse)
    library(ggtext)
    library(glue)
    
    highlight = function(x, pat, color="black", family="") {
      ifelse(grepl(pat, x), glue("<b style='font-family:{family}; color:{color}'>{x}</b>"), x)
    }
    
    head(mtcars) %>% rownames_to_column("cars") %>% 
      ggplot(aes(y = reorder(cars, - drat), 
                 x = drat)) +
      geom_col() +
      scale_y_discrete(labels= function(x) highlight(x, "Datsun 710|Hornet 4", "red")) +
      theme(axis.text.y=element_markdown())
    

    iris %>% 
      ggplot(aes(Species, Petal.Width)) +
      geom_point() + 
      scale_x_discrete(labels=function(x) highlight(x, "setosa", "purple", "Copperplate")) +
      theme(axis.text.x=element_markdown(size=15))
    

    【讨论】:

    • 不错的答案,我现在看到的唯一缺点是ggtext 的 CRAN 版本在 R 4.0.0 上不可用(除非我的 R 安装有问题)
    • 我还没有运行 R 4.0.0,但也许可以尝试安装 ggtext 的开发版本:remotes::install_github("wilkelab/ggtext")
    • 在您的回答中,您颠倒了aes() 中的xy 坐标,并删除了coord_flip()。如果我将这些坐标倒转回来(如我的帖子中所示)并使用coord_flip(),您的代码将不再工作。虽然这不是什么大问题,但我认为在你的回答中值得一提
    • 在当前版本的ggplot2中,不需要指定coord_flip。如果将离散变量映射到 y 轴,ggplot 会自动将绘图渲染为水平图。
    【解决方案2】:

    似乎有一种更简单的方法可以解决这个问题(无需制作自己的贴标机)。只需在theme(axis.text.y) 中指定标签的特定面。请注意,我必须将 x 轴值定义为使标签顺序可预测的因素。

    library(ggplot2)
    
    mtcars$cars <- as.factor(rownames(mtcars))
    bold.cars <- c("Merc 280", "Fiat 128")
    
    bold.labels <- ifelse(levels(mtcars$cars) %in% bold.cars, yes = "bold", no = "plain")
    
    ggplot(mtcars, aes(x = cars, y = drat)) +
      theme(axis.text.y = element_text(face = bold.labels)) +
      geom_col() +
      coord_flip()
    

    【讨论】:

    • 它可以工作但会产生警告:Warning message: Vectorized input to `element_text()` is not officially supported. Results may be unexpected or may change in future versions of ggplot2. 你知道是否可以修复它吗?
    • 运行上面的代码我没有收到任何警告。 ggplot2 3.2.1 版。
    • 我有一个警告ggplot2 3.3.0
    【解决方案3】:

    一种方法是在标签参数中使用expression

    library(ggplot2)
    library(tibble)
    
    ggplot(head(mtcars) %>% rownames_to_column("cars"),
           aes(x = reorder(cars, - drat), 
               y = drat)) +
      geom_col() +
      scale_x_discrete(labels = c("Mazda RX4",
                                  "Mazda RX4 Wag",
                                  expression(bold("Datsun 710")),
                                  expression(bold("Hornet 4 Drive")),
                                  "Hornet Sportabout",
                                  "Valiant")) + 
      coord_flip()    
    

    如果您想以自动方式执行此操作,您可以定义一个自定义粗体函数来制作表达式:

    library(ggplot2)
    library(dplyr)
    library(tibble)
    
    MakeExp <- function(x,y){
      exp <- vector(length = 0, mode = "expression")
      for (i in seq_along(x)) {
        if (i %in% y) exp[[i]] <- bquote(bold(.(x[i])))
        else exp[[i]] <- x[i]
      }
    return(exp)
    }
    
    ggplot(head(mtcars) %>% rownames_to_column("cars"),
           aes(x = reorder(cars, - drat), 
               y = drat)) +
      geom_col() +
      scale_x_discrete(labels = MakeExp(rownames(head(mtcars)),c(3,4))) + 
      coord_flip()            
    
    

    【讨论】:

    • 这种方法的一个缺点是您需要写下所有汽车的名称(在此示例中),是否可以仅将粗体应用于某些汽车名称?
    • @bretauv 我的猜测是,这可以通过自定义贴标功能实现。
    • @bretauv 我编辑了我的答案,给出了一个自定义标签表达式函数的例子。
    • 您的编辑改进了您的答案,但这仍然需要知道与汽车名称相对应的行号,当您有很多名称时,我发现这很烦人
    • 您可以轻松地将y 更改为您想要加粗的名称,并将if 语句更改为if (x[i] %in% y)
    【解决方案4】:

    一种会引发警告的“自动化”(半)方法(见后文,见this issue):

    library(ggplot2)
    library(dplyr)
    library(tibble)
    
    custom_face <- ifelse(row.names(mtcars) %in% c("Hornet 4 Drive","Datsun 710"),
                          "bold","plain")
    head(mtcars) %>% rownames_to_column("cars") %>%
    ggplot(aes(x = reorder(cars, - drat), 
               y = drat)) +
      geom_col() +
      coord_flip() +
      theme(axis.text.y = element_text(face=custom_face))
    

    警告(从关于链接问题的讨论中我不清楚关于此“功能”未来的最终决定是什么)

    警告信息: 官方不支持element_text() 的矢量化输入。 结果可能出乎意料,或者在 ggplot2 的未来版本中可能会发生变化。

    结果

    【讨论】:

    • 我有错误Error in element_text(face = custom_face): object 'custom_face' not found(在新会话中)
    • 您是否按照此答案运行代码?哦,让我编辑。我在其他地方定义了一些其他测试函数
    • 是的,我在新会话中复制并粘贴了您的代码(刚刚添加了必要的library() 调用)
    • 谢谢,我已经编辑过了,现在应该可以使用了。无论如何,虽然我之前已经回答过,但已经添加了类似的答案。
    猜你喜欢
    • 2020-09-24
    • 1970-01-01
    • 2021-12-23
    • 2020-10-19
    • 2015-06-28
    • 1970-01-01
    • 1970-01-01
    • 2018-04-13
    • 1970-01-01
    相关资源
    最近更新 更多