在ggplot2中着色boxplot异常点?

13 graphics r ggplot2

如何在ggplot2中为异常点着色?我希望它们与boxplot本身颜色相同.colour=这还不够.

例:

p <- ggplot(mtcars, aes(factor(cyl), mpg))
p + geom_boxplot(aes(colour=factor(cyl)))
Run Code Online (Sandbox Code Playgroud)

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

> p <- ggplot(mtcars, aes(factor(cyl), mpg))
> p + geom_boxplot(aes(colour=factor(cyl), outlier.colour=factor(cyl)))
Run Code Online (Sandbox Code Playgroud)

cbe*_*ica 25

更新(2015-03-31):请参阅@ tarch的解决方案ggplot2> = 1.0.0

ggplot2<= 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)
Run Code Online (Sandbox Code Playgroud)

带有彩色异常值的boxplot

  • outlier.colour 必须用"ou"写
  • outlier.colour 必须在外面 aes ()

我发布这个作为一个迟到的答案,因为我发现自己一次又一次地看着这个,我也发布了相关的问题Boxplot,如何匹配异常值的颜色来填补美学?

  • 您使用的是什么版本的ggplot2?使用1.0.0,这不会产生彩色异常值 (2认同)
  • @cbeleites查看以下tarch的最新答案,以获得正确的解决方案.`NULL`是异常颜色的默认值,它继承自默认的颜色,因此您必须设置它.我担心我必须对这个职位进行投票,以便现在正确的职位有更好的机会浮动到顶部.我知道你的答案在某个时间点是正确的,但不幸的是,它已经不存在了. (2认同)

Din*_*nre 15

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

帮助文件示例

使用与'geom_boxplot'帮助文件相同的数据:

ggplot(mtcars, aes(x=factor(cyl), y=mpg, col=factor(cyl))) +
    geom_boxplot()
Run Code Online (Sandbox Code Playgroud)

帮助文件演示

着色异常点

现在可能有一种更简化的方法可以做到这一点,但我更喜欢手工计算,所以我不必猜测幕后发生了什么.使用'plyr'软件包,我们可以快速获得使用默认(Tukey)方法确定异常值的上限和下限,该异常值是范围之外的任何点[Q1 - 1.5*IQR,Q3 + 1.5*IQR].Q1和Q3是数据的1/4和3/4分位数,IQR = Q3-Q1.我们可以将这一切写成一个巨大的声明,但由于'plyr'包的'mutate'函数将允许我们引用新创建的列,我们不妨将其拆分以便于读取/调试,如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

我们使用'ddply'函数,因为我们输入数据帧并希望数据帧作为输出("d-> d"ply).上面'ddply'语句中的'mutate'函数保留了原始数据框并添加了其他列,并且规范.(cyl)告诉要为每个'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)))
Run Code Online (Sandbox Code Playgroud)

彩色异常值

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

更新:OP请求更完整地解释此代码中使用的'ddply'函数.这里是:

"plyr"系列函数基本上是一种对数据进行子集化并对数据的每个子集执行函数的方法.在这种特殊情况下,我们有声明:

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)
Run Code Online (Sandbox Code Playgroud)

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

ddply(
Run Code Online (Sandbox Code Playgroud)

我们想在'mtcars'数据框上执行声明,所以我们添加它.

ddply(mtcars, 
Run Code Online (Sandbox Code Playgroud)

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

ddply(mtcars, .(cyl),
Run Code Online (Sandbox Code Playgroud)

下一个参数指定要应用于每个组的函数.我们希望我们的计算向旧数据添加新行,因此我们选择'mutate'函数.这将保留旧数据并将新计算添加为新列.这与其他函数(如'summarize')形成对比,后者删除除分组变量之外的所有旧列.

ddply(mtcars, .(cyl), mutate, 
Run Code Online (Sandbox Code Playgroud)

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

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), 
Run Code Online (Sandbox Code Playgroud)

"Q3"列的计算方法类似.

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), 
Run Code Online (Sandbox Code Playgroud)

幸运的是,使用'mutate'函数,我们可以使用新创建的列作为其他列定义的一部分.这使我们不必编写一个巨大的函数或必须运行多个函数.我们需要在'IQR'变量的四分位数范围的计算中使用'Q1'和'Q3',并且使用'mutate'函数很容易.

ddply(mtcars, .(cyl), mutate, Q1=quantile(mpg, 1/4), Q3=quantile(mpg, 3/4), IQR=Q3-Q1, 
Run Code Online (Sandbox Code Playgroud)

我们终于成为了现在的目标.从技术上讲,我们不需要'Q1','Q3'和'IQR'列,但它确实使我们的下限和上限方程更容易阅读和调试.我们可以像理论公式一样编写表达式: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)
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

只是为了给出一个对比,如果我们使用'summarize'函数执行相同的'ddply'语句,相反,我们会得到所有相同的答案,但没有其他数据的列.

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
Run Code Online (Sandbox Code Playgroud)

  • @ user248237dfsf据我所知,`outlier.colour =`参数不允许使用颜色矢量.您试图在'geom_boxplot'函数的预期行为之外执行某些操作,因此无法在函数内执行此操作.此外,几行代码并不完全是我称之为"非常复杂"的代码.比一个论点更复杂?当然.比编写新的boxplot函数更复杂?不是由一个长镜头. (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()
Run Code Online (Sandbox Code Playgroud)

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

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

update_geom_defaults("point", list(colour = "black"))
Run Code Online (Sandbox Code Playgroud)

通过阅读github上的ggplot2更改日志找到了解决方案:

geom_boxplot()使用默认颜色,大小和形状 的异常值geom_point().更改geom_point()with 的默认值update_geom_defaults()将对异常值应用相同的更改 geom_boxplot().以前无法更改异常值的默认值.(@ThierryO,#757)

也发布在这里:ggplot2 boxplot,我如何匹配异常值的颜色来填补美学?


Did*_*rts 6

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

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

使用plot_Data来自@Dinre答案的数据和代码 - 异常值的颜色取决于因素carb.通过向原始异常值添加参数outlier.shape = NAgeom_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)))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

要改变点的形状:

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)))
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述