【问题标题】:r stacked bargraph with colors representing valuesr 堆积条形图,颜色代表值
【发布时间】:2015-08-09 18:49:15
【问题描述】:

我希望制作一个堆叠条形图,其颜色代表来自单独数据列的值,以及添加准确的颜色条仅使用 R 中的基本图形。还有一篇关于此的帖子,但它非常杂乱无章,最后并没有帮助我回答我的问题。

# create reproducible data
d <- read.csv(text='Day,Location,Length,Amount
            1,4,3,1.1
            1,3,1,.32
            1,2,3,2.3
            1,1,3,1.1
            2,0,0,0
            3,3,3,1.8
            3,2,1,3.54
            3,1,3,1.1',header=T)

# colors will be based on values in the Amount column
v1 <- d$Amount
# make some colors based on Amount - normalized
z <- v1/max(v1)*1000
colrs <- colorRampPalette(c('lightblue','blue','black'))(1000)[z]

# create a 2d table of the data needed for plotting
tab <- xtabs(Length ~ Location + Day, d)
# create a stacked bar plot
barplot(tab,col=colrs,space=0)

# create a color bar
plotr::color.bar

这肯定会生成一个颜色编码的堆叠条形图,但颜色并不能准确地代表数据。

对于第 1 天,位置 4 和位置 1 的颜色应相同。另一个示例,金额列中的第一个和最后一个条目相同,但左列顶部的颜色与右列底部不匹配。

另外,我发现如何在不同的帖子上制作彩条,它使用plotr::color.bar 代码,但plotr 显然不是一个包,我不知道如何继续。

如何让颜色与相应的部分相匹配并添加准确的颜色条?

【问题讨论】:

    标签: r colors bar-chart stacked-chart


    【解决方案1】:

    我希望“相当杂乱无章”的帖子不是我对How to create a time series plot in the style of a horizontal stacked bar plot in r 的回答!没关系,没有冒犯。

    该解决方案可以根据您的数据进行调整,如下所示:

    ## store data
    df <- read.csv(text='Day,Location,Length,Amount\n1,4,3,1.1\n1,3,1,.32\n1,2,3,2.3\n1,1,3,1.1\n2,0,0,0\n3,3,3,1.8\n3,2,1,3.54\n3,1,3,1.1',header=T);
    
    ## extract bar segment lengths from Length and bar segment colors from a function of Amount, both stored in a logical matrix form
    lengths <- xtabs(Length~Location+Day,df);
    amounts <- xtabs(Amount~Location+Day,df);
    colors <- matrix(colorRampPalette(c('lightblue','blue','black'))(1001)[amounts/max(amounts)*1000+1],nrow(amounts));
    
    ## transform lengths into an offset matrix to appease design limitation of barplot(). Note that colors will be flattened perfectly to accord with this offset matrix
    lengthsOffset <- as.matrix(setNames(reshape(cbind(id=1:length(lengths),stack(as.data.frame(unclass(lengths)))),dir='w',timevar='ind')[-1],colnames(lengths)));
    lengthsOffset[is.na(lengthsOffset)] <- 0;
    
    ## draw plot
    barplot(lengthsOffset,col=colors,space=0,xlab='Day',ylab='Length');
    


    备注

    • 在您的问题中,您尝试使用colrs &lt;- colorRampPalette(c('lightblue','blue','black'))(1000)[z] 构建颜色向量,其中z 是转换为“每千”形式的8 个原始Amount 值。这有一个小缺陷,z 元素之一为零,这不是有效的索引值。这就是为什么你有 7 种颜色,而本来应该是 8 种颜色。我在代码中修复了这个问题,将每千分之一的值加 1 并生成 1001 种颜色。
    • 还与生成颜色有关,而不是只生成 8 种颜色(即每个原始 Amount 值一种),我生成了一个完整的颜色矩阵以平行于 lengths 矩阵(您在代码中称为 tab )。这个颜色矩阵实际上可以直接用作传递给barplot()col 参数的颜色向量,因为在内部它被展平为一个向量(至少在概念上)并且将对应于我们将要的偏移条段长度将 height 参数传递给 barplot()(请参阅下一个注释)。
    • 正如我在上述帖子中更详细描述的那样,此解决方案的关键是创建条形段长度的“偏移矩阵”,在相邻列中为零,以便可以为每个段分配不同的颜色。我从lengths 矩阵将其创建为lengthsOffset
    • 请注意,可能有点违反直觉,height 参数中较低的索引值由 barplot() 绘制为较低的段,反之亦然,这意味着当您在终端中打印该数据时,文本显示是垂直的与它在条形图中的显示方式相反。如果您想要相反的顺序,您可以垂直反转 lengthsOffset 矩阵和 colors 向量,但我的代码中没有这样做。

    作为参考,这里是所有的数据结构:

    df;
    ##   Day Location Length Amount
    ## 1   1        4      3   1.10
    ## 2   1        3      1   0.32
    ## 3   1        2      3   2.30
    ## 4   1        1      3   1.10
    ## 5   2        0      0   0.00
    ## 6   3        3      3   1.80
    ## 7   3        2      1   3.54
    ## 8   3        1      3   1.10
    lengths;
    ##         Day
    ## Location 1 2 3
    ##        0 0 0 0
    ##        1 3 0 3
    ##        2 3 0 1
    ##        3 1 0 3
    ##        4 3 0 0
    amounts;
    ##         Day
    ## Location    1    2    3
    ##        0 0.00 0.00 0.00
    ##        1 1.10 0.00 1.10
    ##        2 2.30 0.00 3.54
    ##        3 0.32 0.00 1.80
    ##        4 1.10 0.00 0.00
    colors;
    ##      [,1]      [,2]      [,3]
    ## [1,] "#ADD8E6" "#ADD8E6" "#ADD8E6"
    ## [2,] "#4152F5" "#ADD8E6" "#4152F5"
    ## [3,] "#0000B3" "#ADD8E6" "#000000"
    ## [4,] "#8DB1EA" "#ADD8E6" "#0000FA"
    ## [5,] "#4152F5" "#ADD8E6" "#ADD8E6"
    lengthsOffset;
    ##    1 2 3
    ## 1  0 0 0
    ## 2  3 0 0
    ## 3  3 0 0
    ## 4  1 0 0
    ## 5  3 0 0
    ## 6  0 0 0
    ## 7  0 0 0
    ## 8  0 0 0
    ## 9  0 0 0
    ## 10 0 0 0
    ## 11 0 0 0
    ## 12 0 0 3
    ## 13 0 0 1
    ## 14 0 0 3
    ## 15 0 0 0
    

    【讨论】:

    • 您好,bgoldst,感谢您的意见。您的解决方案似乎确实适用于该示例(与其他示例一样),但在将其应用于更具体的数据集时遇到了问题。我很欣赏深入的答案、其他参考资料和生成颜色的解释。无论出于何种原因,与 Chris 提供的 ggplot2 解决方案相比,您对这个问题的解决方案需要更多的计算时间。我们也缺少此解决方案的彩条。再次感谢!
    【解决方案2】:

    基于以下cmets:

    library(ggplot2)
    ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount, order = Location), stat = "identity") 
    

    【讨论】:

    • 嗨,克里斯 - 我想尝试使用基本图形,但为了澄清起见,我们可以从上面生成的图是准确的减去填充。 x=天,y=长度,填充就是数量。我有 Location 列以确保行在条形图中正确堆叠。 Location=4 在顶部,0 在底部的行。
    • ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount), stat = "identity")在探索了您的 ggplot 解决方案之后 - 位置反转(底部为 4,顶部为 0)。似乎已经得到了正确的配色方案和栏。
    • 您可以使用ggplot(d, aes(x = Day, y = Amount)) + geom_bar(aes(fill = rev(Location)), stat = "identity") 来反转位置顺序(或将列定义为手动设置顺序的因素),但您似乎还是想按金额填写。我不明白你为什么要避免使用 ggplot,但下面的基本解决方案也可以工作(尽管与所有非 ggplot 解决方案一样,我发现整个语法 + 操作很复杂)
    • 嗨,克里斯。当然,我对其他解决方案持开放态度,但希望通过请求基本图形解决方案以某种方式直接反馈。我仍在探索您的解决方案 - 是的,我需要按数量填充颜色,但将条形部分从最低位置堆叠到最高位置。 y 轴仍为 Length,x 轴仍应为 Day。您提供的第二行代码更改了配色方案,但没有重新排列堆叠顺序。 Pafnucy 提供的视觉展示了堆叠的正确排列。
    • 您需要使用order 参数,使用ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount, order = Location), stat = "identity")ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount, order = rev(Location)), stat = "identity"),或者使用因子来预设位置顺序
    【解决方案3】:

    我认为这是定义颜色的错误,条形图只需要 5 种颜色,因为有 5 个位置,其中一种颜色不会被使用,因为位置 1 每天都有零个元素。

    修复:

    colrs <- colorRampPalette(c('yellow', 'lightblue','blue','black', 'lightblue'))(5)
    

    请注意,没有绘制“黄色”,因为它的组中有 0 个观察值(在来自 OP 的样本数据中)

    【讨论】:

    • 嗨 Pafnucy - 我想我对颜色定义错误感到困惑。我想根据从 0 到 1000 的位置为每个数量分配一种颜色,然后依次将这些颜色分配给每个按长度栏的日期。在第一篇文章中,Amount 有 6 个不同的值,colorRampPalette 产生 7 种不同的颜色,它们没有正确分配。您详细说明的方式似乎限制了配色方案。
    猜你喜欢
    • 2017-09-29
    • 1970-01-01
    • 2017-03-31
    • 1970-01-01
    • 1970-01-01
    • 2020-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多