ggplot2 - 如何使用另一个数据框作为查找表来更改构面标签文本

时间:2017-01-16 16:11:41

标签: r ggplot2 facet-wrap

我使用ggplot 2.2.0和R版本3.3.2 w64

根据http://www.cookbook-r.com/Graphs/Facets_(ggplot2)/,我可以指定一个提供构面标签的功能。 我绘制了一项研究的患者数据:

image of plotted patient data

我有一个包含ID和数据的数据框,我有第二个数据框包含一些一般信息(年龄和性别)

patmeta <- data.frame(
 "pat_id"=c(66, 103, 219, 64, 62, 111, 232),
 "gender"=c("f","f","f", "m","f", "f", "f"), 
 "age"=c(56, 32, 73, 58,37,33,52))

我为pat_id定义了一个全局标签函数和一个特殊的函数(pat_id_fac与pat_id相同但作为因子,pat_id是数字)

PatIdLabeller <- function(id) {
    res <- sprintf("Pat %s (%i y, %s)", id,
              subset(patmeta, pat_id == id)$age,
              subset(patmeta, pat_id == id)$gender)
    return(res)
}

globalLabeller <- labeller(
    pat_id_fac = PatIdLabeller,
    pat_id = PatIdLabeller,
    .default = label_both
)

测试PatIdLabeller函数会给出所需的输出(尽管我认为,使用子集不是最优雅的方法),例如

> PatIdLabeller('103')
[1] "Pat 103 (32 y, f)"

但是在ggplot中使用它,ID是正确的,但是年龄和性别都是相同的(patmeta的最后一行),如图所示。

我的qdat的一个子集是以下

structure(list(pat_id = c(103L, 103L, 103L, 64L, 64L, 64L, 66L, 
66L, 66L, 219L, 219L, 219L, 62L, 62L, 62L, 111L, 111L, 111L, 
232L, 232L, 232L), pat_id_fac = structure(c(4L, 4L, 4L, 2L, 2L, 
2L, 3L, 3L, 3L, 6L, 6L, 6L, 1L, 1L, 1L, 5L, 5L, 5L, 7L, 7L, 7L
), .Label = c("62", "64", "66", "103", "111", "219", "232"), 
class = c("ordered", "factor")), 
Activity = structure(c(9L, 3L, 9L, 2L, 9L, 9L, 9L, 
2L, 2L, 3L, 8L, 4L, 2L, 2L, 2L, 4L, 4L, 7L, 2L, 2L, 9L), .Label = c("", 
"Anderes", "Essen", "Hausarbeit", "Hobbies", "Körperpflege", 
"Liegen", "Medienkonsum", "Sozialer Kontakt"), class = "factor")), 
.Names = c("pat_id", "pat_id_fac", "Activity"), row.names = c(1L, 2L, 3L,  
128L, 129L, 130L, 199L, 200L, 201L, 217L, 218L, 219L, 343L, 344L, 345L,   
397L, 398L, 399L, 451L, 452L, 453L), class = "data.frame")


g.bar.activities <-
    ggplot(data=qdat, aes(x=Activity)) +
    geom_bar() +
    facet_wrap(~ pat_id_fac, labeller= globalLabeller)

从其他问题和答案中,我知道我可以定义一个角色向量,但我很懒,并希望重新使用我的patmeta更优雅,因为研究参与者的名单将变得很长并且随着时间的推移而发展。 / p>

使用较小的测试数据集

t <- data.frame("pat_id"=c(103, 103, 103, 219, 219, 219), 
"Activity" = c("sleep", "sleep", "eat", "eat", "eat", "sleep"))
patmeta <- data.frame("pat_id"=c(103, 219), 
"gender"=c("m","f"), "age"=c(32,52))

ggplot(data=t, aes(x=Activity)) + geom_bar() + 
facet_wrap(~pat_id, labeller=globalLabeller)

我得到了我想要的东西。我没有看到差异。

1 个答案:

答案 0 :(得分:1)

似乎子集化工作不正常,可能是因为==试图沿着传入的所有id的长度充当向量。也就是说,它检查pat_id中的每个patmeta是否与传入的pat_id相匹配。排序的差异在某种程度上只留下一个pat_id匹配。

如果您尝试以下任何一项,则可以看到此操作:

PatIdLabeller(c(103, 66))

给出character(0)并发出此警告:

  

在pat_id == id:更长的对象中   长度不是较短物体长度的倍数

因为没有行返回,并且R被强制重复==

中的元素
ggplot(data=head(qdat), aes(x=Activity)) +
  geom_bar() +
  facet_wrap(~ pat_id, labeller= globalLabeller)

再次给出了重复年龄/性别的情节,以及此警告

  

在pat_id == id中:较长的对象长度不是a   多个较短的物体长度

(同上)。

值得注意的是,即使使用较小的数据集,如果您反转新patmeta的行顺序(使219在103之前),则运行您获得的代码

  

FUN(X [[i]],...)出错:输入未知

因为贴标机返回空character()(如上所述)。

我没有很多贴标签的经验(这个答案是探索它们的好机会),但是这个应该可以使用来自left_join的{​​{1}},而不是尝试使用dplyr

==

并使用give:

myLabeller <- function(x){
  lapply(x,function(y){
    toLabel <-
      data.frame(pat_id = y) %>%
      left_join(patmeta)

    paste0("Pat ", toLabel$pat_id
           , " (", toLabel$age, "y, "
           , toLabel$gender, ")")
  })
}

enter image description here

另一种选择是跳过贴标机步骤,只生成您想直接使用的标签。在这里,只需将元数据与患者数据合并(使用ggplot(data=qdat, aes(x=Activity)) + geom_bar() + facet_wrap(~pat_id, labeller=myLabeller) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) 中的left_join),然后使用您想要的格式/样式生成列(此处使用dplyr来自{{ 1}}和mutate)。

dplyr

然后,使用该数据进行绘图,并将新列用于刻面。

paste0

给出

enter image description here

请注意,facet现在按字母顺序排序,但您可以根据需要进行调整,方法是将列设置为具有显式排序级别的因子。