如何将分组箱线图打印到 pdf 文档上并标记异常值

How to print grouped boxplots onto a pdf document and label the outliers

我有一个类似于使用此代码创建的数据框:

Location <- rep(c("FL", "GA", "SC", "NC"), each = 5)
ID <- data.frame(ID=(c(12,122,242,329,595,130,145,245,654,878,863,425,24,92,75,3,200,300,40,500)))
set.seed(1)
Copper <- sample(1:100,20,replace=T)
Iron <- sample(1:100,20,replace=T)
Carbon <- sample(1:100,20,replace=T)
Lead <- sample(1:100,20,replace=T)
Mg <- sample(1:100,20,replace=T)
CaCO <- sample(1:100,20,replace=T)
Zinc <- sample(1:100,20,replace=T)
data <- cbind(Location,State,ID,Copper,Iron,Carbon,Lead,Mg,CaCO,Zinc)

注意:我不知道如何创建一个包含一些极端异常值的模拟数据集,这对这个问题很有用,如果有人想在答案中包含它,那就太棒了。

我可以为按 Location 分组的每个变量 (Copper:Zinc) 创建箱线图,如下所示:

#example shown for Copper
library(tidyverse)
ggplot(data, aes(x=Location, y=Copper, color = Location))+
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust = 1)) +
  theme(legend.position = "none",
        axis.title.y = element_blank()) +
  ggtitle("Copper") + theme(plot.title = element_text(hjust = 0.5))

我一直在为每个变量 (Copper:Zinc) 执行相同的过程。我想知道一种更快的方法来完成此操作 - 无需复制和粘贴那么多 - 并将绘图打印到 pdf 文档中。我必须先使用 pivot_longer() 吗?我还想知道如何使用 ggplot2 仅标记每个图中的异常值?

使用 facet_wrap 在单个图上获得多个面板

无需为每个元素复制代码,您可以使用 ggplot2 中的 facet_wrap 函数将所有箱线图放在一个页面上(您可以在保存后以您的方式像)。 (https://ggplot2.tidyverse.org/reference/facet_wrap.html)

为此,您首先需要重塑数据,以便将所有元素放在一个列中,将所有值放在第二列中,您可以使用 pivot_longer 中的函数来实现此目的19=]:

library(tidyr)
data %>% pivot_longer(.,-c(State,ID), names_to = "Element", values_to = "Value") 

# A tibble: 140 x 4
   State    ID Element Value
   <fct> <dbl> <chr>   <int>
 1 FL       12 Copper     68
 2 FL       12 Iron       89
 3 FL       12 Carbon     44
 4 FL       12 Lead       81
 5 FL       12 Mg         73
 6 FL       12 CaCO       24
 7 FL       12 Zinc       28
 8 FL      122 Copper     39
 9 FL      122 Iron       37
10 FL      122 Carbon     25
# … with 130 more rows

现在,您可以像以前一样获取绘图,除了您指示 ggplot2 使用 facet_wrap(~Element) 为每个元素创建一个面板:

data %>% pivot_longer(.,-c(State,ID), names_to = "Element", values_to = "Value") %>%
  ggplot(aes(x = State, y = Value, color = State))+
  geom_boxplot() +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust = 1)) +
  theme(legend.position = "none",
        axis.title.y = element_blank(),
        axis.title.x = element_blank()) +
  facet_wrap(.~Element)

用 ID 标记异常值

要用 ID 标记离群值,您可以先创建一个新列来标识它们。在这里,我使用 dplyr 创建一个新列(在旋转数据框之后)以确定每个点是否是异常值:

DATA <- data %>% pivot_longer(.,-c(State,ID), names_to = "Element", values_to = "Value") %>%
  group_by(State, Element) %>%
  mutate(Outlier = ifelse(Value > quantile(Value,0.75)+1.5*IQR(Value) | Value < quantile(Value,0.25)-1.5*IQR(Value), "Out","in"))

# A tibble: 140 x 5
# Groups:   State, Element [28]
   State    ID Element Value Outlier
   <fct> <dbl> <chr>   <dbl> <chr>  
 1 FL       12 Copper     68 in     
 2 FL       12 Iron       37 in     
 3 FL       12 Carbon     70 in     
 4 FL       12 Lead       87 in     
 5 FL       12 Mg         45 in     
 6 FL       12 CaCO       59 in     
 7 FL       12 Zinc       43 in     
 8 FL      122 Copper     39 in     
 9 FL      122 Iron       89 in     
10 FL      122 Carbon     40 in     
# … with 130 more rows

现在,我们可以使用 geom_text(或 ggrepel 包中的 geom_text_repel)通过对数据框进行子集化以仅保留标记为异常值的点并使用 label = ID 作为 aes 中的参数以显示每个异常值的 ID:

library(ggplot2)
library(ggrepel)
ggplot(DATA, aes(x = State, y = Value, color = State))+
  geom_boxplot() +
  geom_text_repel(data = subset(DATA, Outlier == "Out"), aes(label = ID))+
  theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust = 1)) +
  theme(legend.position = "none",
        axis.title.y = element_blank(),
        axis.title.x = element_blank()) +
  facet_wrap(.~Element, scales = "free")

遍历情节以每页只获得一个情节

如果您希望每页只绘制一个元素并遍历所有元素,从 DATA 开始(识别异常值),您可以通过创建一个遍历 "Element" 的每个值for 循环:

element <- unique(DATA$Element) 
for(i in 1:length(element))
{
  g <- ggplot(subset(DATA, Element == element[i]), aes(x = State, y = Value, color = State))+
    geom_boxplot() +
    geom_text_repel(data = subset(DATA, Element == element[i] & Outlier == "Out"), aes(label = ID))+
    theme(axis.text.x = element_text(angle = 90, vjust = 0.3, hjust = 1)) +
    theme(legend.position = "none",
          axis.title.y = element_blank(),
          axis.title.x = element_blank())  +
    ggtitle(element[i]) + theme(plot.title = element_text(hjust = 0.5))
  ggsave(g,filename = paste("test",element[i],".png"), width = 5, height =5, units = "in" )
}

在这里,我将其保存为 png,但您可以对 pdf 或任何其他格式执行相同的操作。