r 堆叠条形图,颜色代表值
r stacked bargraph with colors representing values
我想制作一个堆叠条形图,其颜色代表来自单独数据列的值,并添加一个准确的颜色条 仅使用 R 中的基本图形。还有一个 post 与此有关,但它非常混乱,最终无法帮助我回答我的问题。
# 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 的颜色应该相同。另一个示例,Amount 列中的第一个和最后一个条目是相同的,但左列顶部的颜色与右列底部的颜色不匹配。
此外,我发现了如何在不同的 post 上制作颜色条,它使用 plotr::color.bar
代码,但 plotr
显然不是一个包,我是不确定如何进行。
如何让颜色与适当的部分相匹配并添加准确的颜色条?
基于以下评论:
library(ggplot2)
ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount, order = Location), stat = "identity")
我认为这是定义颜色的错误,条形图只需要 5 种颜色,因为有 5 个位置,其中一种颜色不会被使用,因为位置 1 每天都有零个元素。
修复:
colrs <- colorRampPalette(c('yellow', 'lightblue','blue','black', 'lightblue'))(5)
请注意,'yellow' 未绘制,因为它的组中有 0 个观察值(来自 OP 的示例数据)
希望"pretty disorganized"post不是我对的回答!没关系,没有冒犯。
解决方案可以根据您的数据进行如下调整:
## 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 <- colorRampPalette(c('lightblue','blue','black'))(1000)[z]
构建颜色向量,其中 z
是 8 个原始 Amount
值转换为 "per mille" 形式。这有一个小缺陷,其中一个 z
元素为零,这不是有效的索引值。这就是为什么你有 7 种颜色,而它应该是 8 种。我在我的代码中通过将每千分之一的值加 1 并生成 1001 种颜色来修复这个问题。
- 也与生成颜色有关,而不是仅仅生成 8 种颜色(即每个原始
Amount
值一个),我生成了一个完整的颜色矩阵来平行 lengths
矩阵(你称之为tab
在你的代码中)。这个颜色矩阵实际上可以直接用作传递给 barplot()
的 col
参数的颜色向量,因为它在内部被展平为一个向量(至少在概念上)并且将与偏移条段长度相对应我们将传递给 barplot()
作为 height
参数(见下一个注释)。
- 这个解决方案的关键,正如我在前面提到的 post 中更详细地描述的那样,正在创建一个 "offset matrix" 的条形段长度,在相邻列中使用零,这样不同的颜色可以分配给每个段。我从
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
我想制作一个堆叠条形图,其颜色代表来自单独数据列的值,并添加一个准确的颜色条 仅使用 R 中的基本图形。还有一个 post 与此有关,但它非常混乱,最终无法帮助我回答我的问题。
# 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 的颜色应该相同。另一个示例,Amount 列中的第一个和最后一个条目是相同的,但左列顶部的颜色与右列底部的颜色不匹配。
此外,我发现了如何在不同的 post 上制作颜色条,它使用 plotr::color.bar
代码,但 plotr
显然不是一个包,我是不确定如何进行。
如何让颜色与适当的部分相匹配并添加准确的颜色条?
基于以下评论:
library(ggplot2)
ggplot(d, aes(x = Day, y = Length)) + geom_bar(aes(fill = Amount, order = Location), stat = "identity")
我认为这是定义颜色的错误,条形图只需要 5 种颜色,因为有 5 个位置,其中一种颜色不会被使用,因为位置 1 每天都有零个元素。
修复:
colrs <- colorRampPalette(c('yellow', 'lightblue','blue','black', 'lightblue'))(5)
请注意,'yellow' 未绘制,因为它的组中有 0 个观察值(来自 OP 的示例数据)
希望"pretty disorganized"post不是我对
解决方案可以根据您的数据进行如下调整:
## 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 <- colorRampPalette(c('lightblue','blue','black'))(1000)[z]
构建颜色向量,其中z
是 8 个原始Amount
值转换为 "per mille" 形式。这有一个小缺陷,其中一个z
元素为零,这不是有效的索引值。这就是为什么你有 7 种颜色,而它应该是 8 种。我在我的代码中通过将每千分之一的值加 1 并生成 1001 种颜色来修复这个问题。 - 也与生成颜色有关,而不是仅仅生成 8 种颜色(即每个原始
Amount
值一个),我生成了一个完整的颜色矩阵来平行lengths
矩阵(你称之为tab
在你的代码中)。这个颜色矩阵实际上可以直接用作传递给barplot()
的col
参数的颜色向量,因为它在内部被展平为一个向量(至少在概念上)并且将与偏移条段长度相对应我们将传递给barplot()
作为height
参数(见下一个注释)。 - 这个解决方案的关键,正如我在前面提到的 post 中更详细地描述的那样,正在创建一个 "offset matrix" 的条形段长度,在相邻列中使用零,这样不同的颜色可以分配给每个段。我从
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