这是一个玩具data.frame
,它说明了问题(最基本的版本,即以后会有额外的皱纹):
df <- read.table(textConnection(
"toxin dose x y
A 1 0.851 0.312
A 10 0.268 0.443
A 100 0.272 0.648
B 1 0.981 0.015
B 10 0.304 0.658
B 100 0.704 0.821
C 1 0.330 0.265
C 10 0.803 0.167
C 100 0.433 0.003
D 1 0.154 0.611
D 10 0.769 0.616
D 100 0.643 0.541
"), header = TRUE)
我想制作这些数据的散点图,其中毒素由点的色调指示,剂量由它们的亮度指示(对于第一近似,低剂量应对应于高亮度)。
此可视化问题特别具有挑战性的方面是图例必须是二维颜色网格(而不是一维颜色 bar ),使用与toxin
变量对应的行以及与dose
对应的列(或其变换)。
我上面提到的额外皱纹是数据实际上包括一个对照观察,其中剂量与所有其他剂量不同(注意下面的毒素=“Z”行):
df <- read.table(textConnection(
"toxin dose x y
A 1 0.851 0.312
A 10 0.268 0.443
A 100 0.272 0.648
B 1 0.981 0.015
B 10 0.304 0.658
B 100 0.704 0.821
C 1 0.330 0.265
C 10 0.803 0.167
C 100 0.433 0.003
D 1 0.154 0.611
D 10 0.769 0.616
D 100 0.643 0.541
Z 0.001 0.309 0.183
"), header = TRUE)
对照(“Z”)毒素的点应该是单个灰点。 (如果2-d颜色网格图例不包含控制值,则可以,但在这种情况下,应该至少有一个图例可以恰当地标识其点。)
总之,问题分为三个部分:
以下是我迄今为止所管理的内容。
我能想到解决问题第一个方面的唯一方法是为每个毒素设计一个不同的层,并根据剂量使用颜色渐变。
不幸的是,似乎没有办法为每个图层指定不同的渐变比例。
更具体地说,我首先定义以下内容:
library(ggplot2)
hues <- RColorBrewer::brewer.pal(4, "Set1")
gradient <- function (hue_index) {
scale_color_gradient(high = hues[hue_index],
low = "white",
trans = "log",
limits = c(0.1, 100),
breaks = c(1, 10, 100))
}
baseplot <- ggplot(mapping = aes(x = x, y = y, color = dose))
第一层本身看起来很有希望:
(
baseplot
+ geom_point(data = subset(df, toxin == "A"), size = 4)
+ gradient(1)
)
但是当我添加第二层......
(
baseplot
+ geom_point(data = subset(df, toxin == "A"), size = 4)
+ gradient(1)
+ geom_point(data = subset(df, toxin == "B"), size = 4)
+ gradient(2)
)
...我收到以下警告:
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the existing scale.
而且,当然,这是我得到的情节:
我无法找到一种方法来定义不同的图层,每个图层都有自己的色阶。
答案 0 :(得分:1)
它必须是传奇的网格吗?如果你愿意有一个毒素(颜色)的传说和剂量(alpha)的第二个图例,你可以使用它(并设置颜色/填充对你的数据有意义)
df$dose <- factor(df$dose)
ggplot(
df
, aes(x = x, y = y
, col = toxin
, alpha = dose)
) +
geom_point(size = 4)
如果它确实必须是图例的矩阵,你可以自己制作矩阵,然后将它们组合在图上。你将失去一些灵活性,并需要仔细设置,但这应该是一般的(注意我使用最小的主题,因为它似乎最好的传奇 - 显然个人喜好):
theme_set(theme_minimal())
mainPlot <-
ggplot(
df
, aes(x = x, y = y
, col = toxin
, alpha = dose)
) +
geom_point(size = 4)
mainPlot
allLevels <-
expand.grid(toxin = levels(df$toxin)
, dose = levels(df$dose))
legendPlot <-
ggplot(
allLevels
, aes(x = toxin, y = dose
, col = toxin
, alpha = dose)
) +
geom_point(size = 4)
legendPlot
library(gridExtra)
grid.arrange(
mainPlot +
theme(legend.position = "none")
, legendPlot +
theme(legend.position = "none") +
ggtitle("Legend")
, layout_matrix =
matrix(c(1,1,1,NA,2,NA)
, ncol = 2)
, widths=c(2,1)
, heights = c(1,2,1)
)
答案 1 :(得分:0)
此解决方案是对this answer中给出的解决方案的改编。它不会真正做出问题所要求的问题(解决方案的大部分解决方案都不是由ggplot2
完成的,而且传说并不是那么清晰) ,但对于这个问题,这可能是baseplot <- ggplot(data = df, mapping = aes(x = x, y = y))
palette <- function (name, indices = c(3, 5, 7)) {
RColorBrewer::brewer.pal(9, name)[indices]
}
colors <- c(as.vector(sapply(c("Reds", "Blues", "Greens", "Purples"), palette)),
"white")
labels <- mapply(function(toxin, dose) {
paste(toxin, as.character(dose), sep = " @ ")
},
df$toxin, df$dose)
(
baseplot + geom_point(mapping = aes(color = interaction(dose, toxin)),
size = 4)
+ scale_color_manual(name = "toxin @ dose",
values = colors,
labels = labels)
+ guides(color = guide_legend(nrow = 5, byrow = TRUE))
)
最好的。
{{1}}
以下是输出结果: