在ggplot2中着色boxplot异常点?

时间:2013-03-07 14:01:43

标签: r graphics ggplot2

如何在ggplot2中为异常点着色?我希望它们与boxplot本身颜色相同。 colour=不足以做到这一点。

示例:

p <- ggplot(mtcars, aes(factor(cyl), mpg))
p + geom_boxplot(aes(colour=factor(cyl)))

我也希望通过factor(cyl)为异常值着色。这不起作用:

> p <- ggplot(mtcars, aes(factor(cyl), mpg))
> p + geom_boxplot(aes(colour=factor(cyl), outlier.colour=factor(cyl)))

6 个答案:

答案 0 :(得分:24)

更新(2015-03-31):见@tarch's solution for ggplot2 >= 1.0.0

ggplot2&lt; = 0.9.3的解决方案如下。


正如@koshke所说,通过设置outlier.colour = NULL

,现在可以轻松地将异常值设置为与框的线条不同(不是填充颜色)
p <- ggplot(mtcars, aes(x=factor(cyl), y=mpg, col=factor(cyl)))
p + geom_boxplot(outlier.colour = NULL)

boxplot with coloured outliers

  • outlier.colour必须使用“ou”
  • 编写
  • outlier.colour必须在aes ()
  • 之外

我发布这是一个迟到的答案,因为我发现自己一遍又一遍地看着它,我也发布了相关的问题Boxplot, how to match outliers' color to fill aesthetics?

答案 1 :(得分:15)

为了使离群点的颜色与箱图相同,您需要计算异常值并分别绘制它们。据我所知,用于着色异常值的内置选项将所有异常值都颜色相同。

帮助文件示例

使用与&#39; geom_boxplot&#39;相同的数据帮助文件:

ggplot(mtcars, aes(x=factor(cyl), y=mpg, col=factor(cyl))) +
    geom_boxplot()

help file demo

着色离群点

现在可能有一种更简化的方法来做到这一点,但我更喜欢手工计算,所以我不必猜测引擎盖下发生的事情。使用&#39; plyr&#39;包,我们可以快速获得使用默认(Tukey)方法确定异常值的上限和下限,这是超出范围[Q1 - 1.5 * IQR,Q3 + 1.5 * IQR]的任何点。 Q1和Q3是数据的1/4和3/4分位数,IQR = Q3-Q1。我们可以把这一切都写成一个巨大的陈述,但是因为&#39; plyr&#39;包装变种&#39;函数将允许我们引用新创建的列,我们不妨将其拆分以便于读取/调试,如下所示:

library(plyr)
plot_Data <- ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, upper.limit=Q3+1.5*IQR, lower.limit=Q1-1.5*IQR)

我们使用&#39; ddply&#39;函数,因为我们输入数据帧并希望数据帧作为输出(&#34; d-&gt; d&#34; ply)。 &#39;变异&#39;功能在上面&#39; ddply&#39;声明保留原始数据框并添加其他列,.(cyl)的规范告诉我们要计算每个分组的函数。值。

此时,我们现在可以绘制箱线图,然后用新的彩色点覆盖异常值。

ggplot() +
    geom_boxplot(data=plot_Data, aes(x=factor(cyl), y=mpg, col=factor(cyl))) + 
    geom_point(data=plot_Data[plot_Data$mpg > plot_Data$upper.limit | plot_Data$mpg < plot_Data$lower.limit,], aes(x=factor(cyl), y=mpg, col=factor(cyl)))

colored outliers

我们在代码中所做的是指定一个空的&#39; ggplot&#39;图层,然后使用独立数据添加boxplot和点几何。 boxplot几何可以使用原始数据框,但我正在使用我们新的&#39; plot_Data&#39;要保持一致。然后,点几何图形仅绘制异常点,使用我们新的&quot; lower.limit&#39;和&#39; upper.limit&#39;用于确定异常状态的列。因为我们对&#39; x&#39;使用相同的规范。和&#39; col&#39;美学论证,颜色在箱形图和相应的异常点之间神奇地匹配。

更新:OP要求对“ddply”进行更全面的解释。此代码中使用的函数。这是:

&#39; plyr&#39;函数族基本上是一种对数据进行子集化并对每个数据子集执行函数的方法。在这种特殊情况下,我们有声明:

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, upper.limit=Q3+1.5*IQR, lower.limit=Q1-1.5*IQR)

让我们按照语句写的顺序将其分解。首先,选择&#39; ddply&#39;功能。我们想要计算每个值的下限和上限。在&#39; mtcars&#39;数据。我们可以写一个&#39; for&#39;循环或其他语句来计算这些值,但之后我们将不得不再写一个逻辑块来评估异常值状态。相反,我们想要使用&#39; ddply&#39;计算下限和上限并将这些值添加到每一行。我们选择&#39; ddply&#39; (与'dlply&#39;,&#39; d_ply&#39;等)相反,因为我们正在输入数据帧并希望将数据帧作为输出。这给了我们:

ddply(

我们希望在&#39; mtcars&#39;上执行声明。数据框,所以我们添加。

ddply(mtcars, 

现在,我们想要使用&#39; cyl&#39;来执行我们的计算。值作为分组变量。我们使用&#39; plyr&#39;函数.()引用变量本身而不是变量的值,如下所示:

ddply(mtcars, .(cyl),

下一个参数指定要应用于每个组的函数。我们希望我们的计算为旧数据添加新行,因此我们选择“变异”#39;功能。这将保留旧数据并将新计算添加为新列。这与其他函数形成对比,例如&#39; summary&#39 ;,删除除分组变量之外的所有旧列。

ddply(mtcars, .(cyl), mutate, 

最后一系列参数是我们想要创建的所有新数据列。我们通过指定名称(未引用的)和表达式来定义它们。首先,我们创建了&#39; Q1&#39;列。

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), 

&#39; Q3&#39;列的计算方法类似。

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), 

幸运的是,随着变异&#39;函数,我们可以使用新创建的列作为其他列定义的一部分。这使我们不必编写一个巨大的函数或必须运行多个函数。我们需要使用&#39; Q1&#39;和&#39; Q3&#39;在计算IQR&#39;的四分位数范围时变量,并且“变异”变得容易。功能

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, 

我们终于想到了现在的位置。从技术上讲,我们不需要第一季度,第三季度和第三季度的IQR&#39;列,但它确实使我们的下限和上限方程更容易阅读和调试。我们可以像理论公式一样编写表达式:limits=+/- 1.5 * IQR

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, upper.limit=Q3+1.5*IQR, lower.limit=Q1-1.5*IQR)

为了便于阅读,删除了中间列,这就是新数据框的样子:

plot_Data[, c(-3:-11)]
#     mpg cyl    Q1    Q3  IQR upper.limit lower.limit
# 1  22.8   4 22.80 30.40 7.60      41.800      11.400
# 2  24.4   4 22.80 30.40 7.60      41.800      11.400
# 3  22.8   4 22.80 30.40 7.60      41.800      11.400
# 4  32.4   4 22.80 30.40 7.60      41.800      11.400
# 5  30.4   4 22.80 30.40 7.60      41.800      11.400
# 6  33.9   4 22.80 30.40 7.60      41.800      11.400
# 7  21.5   4 22.80 30.40 7.60      41.800      11.400
# 8  27.3   4 22.80 30.40 7.60      41.800      11.400
# 9  26.0   4 22.80 30.40 7.60      41.800      11.400
# 10 30.4   4 22.80 30.40 7.60      41.800      11.400
# 11 21.4   4 22.80 30.40 7.60      41.800      11.400
# 12 21.0   6 18.65 21.00 2.35      24.525      15.125
# 13 21.0   6 18.65 21.00 2.35      24.525      15.125
# 14 21.4   6 18.65 21.00 2.35      24.525      15.125
# 15 18.1   6 18.65 21.00 2.35      24.525      15.125
# 16 19.2   6 18.65 21.00 2.35      24.525      15.125
# 17 17.8   6 18.65 21.00 2.35      24.525      15.125
# 18 19.7   6 18.65 21.00 2.35      24.525      15.125
# 19 18.7   8 14.40 16.25 1.85      19.025      11.625
# 20 14.3   8 14.40 16.25 1.85      19.025      11.625
# 21 16.4   8 14.40 16.25 1.85      19.025      11.625
# 22 17.3   8 14.40 16.25 1.85      19.025      11.625
# 23 15.2   8 14.40 16.25 1.85      19.025      11.625
# 24 10.4   8 14.40 16.25 1.85      19.025      11.625
# 25 10.4   8 14.40 16.25 1.85      19.025      11.625
# 26 14.7   8 14.40 16.25 1.85      19.025      11.625
# 27 15.5   8 14.40 16.25 1.85      19.025      11.625
# 28 15.2   8 14.40 16.25 1.85      19.025      11.625
# 29 13.3   8 14.40 16.25 1.85      19.025      11.625
# 30 19.2   8 14.40 16.25 1.85      19.025      11.625
# 31 15.8   8 14.40 16.25 1.85      19.025      11.625
# 32 15.0   8 14.40 16.25 1.85      19.025      11.625

只是为了给对比,如果我们要做同样的事情&#39; ddply&#39;声明&#39;总结&#39;相反,我们会得到所有相同的答案,但没有其他数据的列。

ddply(mtcars, .(cyl), summarize, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, upper.limit=Q3+1.5*IQR, lower.limit=Q1-1.5*IQR)
#   cyl    Q1    Q3  IQR upper.limit lower.limit
# 1   4 22.80 30.40 7.60      41.800      11.400
# 2   6 18.65 21.00 2.35      24.525      15.125
# 3   8 14.40 16.25 1.85      19.025      11.625

答案 2 :(得分:15)

我找到了一个解决方案,即设置geom_boxplot(outlier.colour = NULL)在最新版本的R中不再起作用(@hamy谈论ggplot2的1.0.0版本)。

为了复制@cbeleites提出的行为,您只需使用以下代码:

update_geom_defaults("point", list(colour = NULL))
m <- ggplot(movies, aes(y = votes, x = factor(round(rating)),
            colour = factor(Animation)))
m + geom_boxplot() + scale_y_log10()

如预期的那样,这会生成带有与线条颜色匹配的点的图。

当然,如果他需要绘制多个图表,应该记得恢复默认值:

update_geom_defaults("point", list(colour = "black"))

通过阅读github上的ggplot2 changelog找到解决方案:

  

geom_boxplot()的异常值使用默认颜色,大小和形状   geom_point()。使用更改geom_point()的默认值   update_geom_defaults()会将相同的更改应用于异常值   geom_boxplot()。之前没有更改异常值的默认值   可能。 (@ThierryO,#757)

也在此发布:ggplot2 boxplot, how do i match the outliers' color to fill aesthetics?

答案 3 :(得分:6)

如果需要根据不同的因素(用于制作箱线图组的不同因素)改变异常点的形状或颜色,则可以调整@Dinre的答案。

只有当颜色不用于箱图本身时才能改变点的颜色(你不能将两个变量用于颜色)。

使用数据plot_Data和@Dinre答案中的代码 - 异常值的颜色取决于因子carb。通过向outlier.shape = NA添加参数geom_boxplot(),可以删除原始异常值,以确保它们不会被geom_point()过度绘制。

ggplot() +
  geom_boxplot(data=plot_Data, aes(x=factor(cyl), y=mpg),outlier.shape = NA) + 
  geom_point(data=plot_Data[plot_Data$mpg > plot_Data$upper.limit | 
                              plot_Data$mpg < plot_Data$lower.limit,], 
             aes(x=factor(cyl), y=mpg, color=factor(carb)))

enter image description here

更改点的形状:

ggplot() +
  geom_boxplot(data=plot_Data, aes(x=factor(cyl), y=mpg),outlier.shape = NA) + 
  geom_point(data=plot_Data[plot_Data$mpg > plot_Data$upper.limit | 
                              plot_Data$mpg < plot_Data$lower.limit,], 
             aes(x=factor(cyl), y=mpg, shape=factor(carb)))

enter image description here

答案 4 :(得分:3)

异常值会在ggplot2 * 1.0.1.9003中再次自动继承该框中的颜色。

https://github.com/hadley/ggplot2/issues/1400

```{r}
library(ggplot2)
point_size=10
ggplot(mtcars, aes(x=factor(cyl), y=mpg, col=factor(cyl))) +
geom_boxplot(outlier.size = point_size)
```

Boxplot

答案 5 :(得分:0)

以防万一,您真的想将盒子保持黑色:

另一种可能的解决方案是

  1. 在变量中存储点是否为离群值
  2. 使用outlier.color = NA抑制异常值绘制,并且
  3. 仅绘制那些离群点,并在对col的调用中使用geom_point()美学

第1步:定义一个函数来确定一个点是否为离群值:

is.outlier <- function (x) {
  x < quantile(x, .25) - 1.5 * IQR(x) |
    x > quantile(x, .75) + 1.5 * IQR(x)
}

第2步:使用此功能对数据进行分组并计算离群值

diamonds %>% group_by(cut) %>%
  mutate(outlier.p = is.outlier(price)) %>%
  ungroup() -> diamonds

第3步:创建情节

ggplot(diamonds, aes(x = cut, y = price, fill = cut)) +
  geom_boxplot(outlier.color = NA) +
  geom_point(data = diamonds[diamonds$outlier.p,], aes(col = cut))

请注意,您必须在geom_point()调用(最后一行)中对数据集进行子集化,以免绘制所有点。

Plot