首页 > 解决方案 > 如何将分组箱线图打印到 pdf 文档上并标记异常值

问题描述

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

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)

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

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

#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 仅标记每个图中的异常值?

标签: rloopsggplot2boxplot

解决方案


用于在单个facet_wrap图上获取多个面板

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

为此,您首先需要重塑数据,以便将所有元素放在单个列中,并将所有值放在第二列中,您可以使用以下pivot_longer函数来实现tidyr

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(或geom_text_repelggrepel包中)通过子集数据框来标记此异常值,以仅保留标记为异常值的点并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(识别出异常值)开始,您可以通过创建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 或任何其他格式执行相同的操作。


推荐阅读