带有映射到 x 的离散变量的刻度标签中的下标

Posted

技术标签:

【中文标题】带有映射到 x 的离散变量的刻度标签中的下标【英文标题】:Subscripts in tick labels with a discrete variable mapped to x 【发布时间】:2020-11-21 09:43:13 【问题描述】:

我想知道如何在我的 x 轴刻度标签中添加下标。不像大多数其他帖子那样在轴标签中,因此来自数据框中已经存在的值。

这是一个可重现的代码示例,我希望括号中的字母是下标。

p_t<- c(rep("FW - P[H]",3),rep("FW - P[L]",3),rep("FW - F",3),rep("FW - SSWB",3),rep("C - F",3),rep("C - P[L]",3),rep("C - P[H]",3))
s_t<-rep(c("A","B","C"),7)
c_t <-c(0,1,2,+
              0,3,2,+
              0,4,3,+
              0,3,4,+
              0,6,5,+
              0,2,4,+
              0,7,2)
df_t1<-data.frame(p_t,s_t,c_t)

ggplot(data=df_t1,aes(y=c_t, x=p_t,fill = s_t))+ 
  geom_bar(stat="identity",
           color="black")

【问题讨论】:

一个很好的问题,有几个不同的可能答案。我已经更改了问题标题,使其更具描述性,并且这样对那些将来搜索的人更有用。我还稍微编辑了问题的文本,以匹配“ggplot2”文档和书籍中使用的术语。 【参考方案1】:

一种可能的方法是使用最近发布的包“ggtext”,但它的使用需要更改示例数据中下标的编码,因为“ggtetxt”实现了对 Markdown 和 html 标记的支持。在第一个代码块中,我更改了示例数据,但如果数据与问题中一样,则可以使用gsub(),如第二个代码块所示,将方括号替换为 HTML 编码的下标-飞。

library(ggplot2)
library(ggtext)

p_t <- c(rep("FW-P<sub>H</sub>", 3), rep("FW-P<sub>L</sub>", 3), rep("FW-F", 3),
        rep("FW-SSWB", 3), rep("C-F", 3), rep("C-P<sub>L</sub>", 3),
        rep("C-P<sub>H</sub>", 3))
s_t <- rep(c("A", "B", "C"), 7)
c_t <- c(0, 1, 2, +0, 3, 2, +0, 4, 3, +0, 3, 4, +0, 6, 5, +0, 2, 4, +0, 7, 2)
df_t1 <- data.frame(p_t, s_t, c_t)

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) + 
  geom_bar(stat = "identity",
           color = "black") +
  theme(axis.text.x = element_markdown())

可以在 scale_x_discrete() 中即时完成字符串替换,以便根据需要自动转换为 HTML 标记。

p_t <- c(rep("FW - P[H]", 3), rep("FW - P[L]", 3), rep("FW - F", 3),
         rep("FW - SSWB", 3), rep("C - F", 3), rep("C - P[L]", 3),
         rep("C - P[H]", 3))
s_t <- rep(c("A", "B", "C"), 7)
c_t <- c(0, 1, 2, +0, 3, 2, +0, 4, 3, +0, 3, 4, +0, 6, 5, +0, 2, 4, +0, 7, 2)
df_t1 <- data.frame(p_t, s_t, c_t)

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) + 
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete(labels = function(x) gsub("\\[", "<sub>", gsub("\\]", "</sub>", x))) +
  theme(axis.text.x = element_markdown()) 

注意:刻度标签与使用 R 表达式时不完全相同,因为此处的字符保持不变,并且既不添加也不修改短划线周围的间距。在这种情况下,破折号明显更短。

【讨论】:

【参考方案2】:

一种基于 'ggplot2' 的方法是将刻度标签设置为 R 表达式。 (此答案中的最后一个代码块是最佳答案,而其他代码块试图给出更一般的答案并提出替代方案。)

我们可以使用scale_x_discrete() 轻松地用 R 表达式替换字符数据值。但如此处所示,只有当我们使用有效的 R 名称作为数据值字符串时,这才是简单的。 (图中的列根据p_t 中存储的值按字母顺序显示,除非使用breaks 参数更改此顺序为scale_x_discrete,因此此示例的顺序不同。)

p_t <- c(rep("a", 3), rep("b", 3), rep("c", 3),
    rep("d", 3), rep("e", 3), rep("f", 3),
    rep("g", 3))
s_t <- rep(c("A", "B", "C"), 7)
c_t <- c(0, 1, 2, +0, 3, 2, +0, 4, 3, +0, 3, 4, +0, 6, 5, +0, 2, 4, +0, 7, 2)
df_t1 <- data.frame(p_t, s_t, c_t)

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete(labels = c(a = expression(FW - P[H]), 
                              b = expression(FW - P[L]), 
                              c = expression(FW - F),
                              d = expression(FW - SSWB), 
                              e = expression(C - F), 
                              f = expression(C - P[L]),
                              g = expression(C - P[H])))

使用命名的表达式向量转换数据中的值。上面的代码还不是问题的完整答案,但它比正确的答案更容易理解,我在下面分两个阶段展示。不同之处在于我们需要在创建标签向量时使用反引号来保护名称,因为数据值包含在 R nanes 中使用时需要特殊处理的字符。

p_t <- c(rep("FW - P[H]", 3), rep("FW - P[L]", 3), rep("FW - F", 3),
    rep("FW - SSWB", 3), rep("C - F", 3), rep("C - P[L]", 3),
    rep("C - P[H]", 3))
s_t <- rep(c("A", "B", "C"), 7)
c_t <- c(0, 1, 2, +0, 3, 2, +0, 4, 3, +0, 3, 4, +0, 6, 5, +0, 2, 4, +0, 7, 2)
df_t1 <- data.frame(p_t, s_t, c_t)

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete(labels = c(`FW - P[H]` = expression(FW - P[H]), 
                              `FW - P[L]` = expression(FW - P[L]), 
                              `FW - F` = expression(FW - F),
                              `FW - SSWB` = expression(FW - SSWB), 
                              `C - F` = expression(C - F), 
                              `C - P[L]` = expression(C - P[L]),
                              `C - P[H]` = expression(C - P[H])))

我展示了这些更简单的案例,因为问题非常具体,对于大多数未来的读者来说,其中一个更简单的答案可能就是他们所需要的。这种方法可用于选择性地替换单个刻度标签,而不是全部替换,如上所示。

我们还可以自动构建作为参数传递给labels 的向量。

labels.vec <- parse(text = unique(df$p_t))
names(labels.vec) <- unique(df$p_t)

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete(labels = c(labels.vec))

此代码只要求df$p_t 中的值可以解析为R 表达式。换句话说,这个解决方案完全由存储在数据框中的值驱动。

最简单且推荐的方法是动态解析。由于parse()定义中的参数命名和位置,我们不能直接将parse作为参数传递给参数labels,我们需要定义一个匿名函数作为包装器。

ggplot(data = df_t1, aes(y = c_t, x = p_t, fill = s_t)) +
  geom_bar(stat = "identity",
           color = "black") +
  scale_x_discrete(labels = function(x) parse(text = x))

最后一个示例与使用“ggtext”一样简单或更简单,但不允许使用嵌入的 HTML 标记添加颜色等,就像使用“ggtext”一样。

注意:标签与使用 'ggtext' 时的标签并不完全相同,因为此处的“减号”字符用于短划线,并且这些短划线周围的间距已调整为排版数学表达式。

【讨论】:

以上是关于带有映射到 x 的离散变量的刻度标签中的下标的主要内容,如果未能解决你的问题,请参考以下文章

在 x 轴上的离散组之间添加刻度

ggplot:离散x轴的线图

按频率/值排序离散 x 比例

离散化

在 matplotlib 中创建一个离散的颜色条

离散化