Обратите внимание на следующее. Почему я не получаю точную заливку и маркировку? Почему я получаю только одноцветную заливку? Обратите внимание, что версия без цикла работает отлично
data(iris)
xx <- list(iris, iris)
xx[[1]]$Sepal.Length <- rnorm(150)
xx[[2]]$Sepal.Length <- rnorm(150,mean = 10)
cols <- c("low" = "#e41a1c", "high"= "#377eb8")
p2 <- p <- ggplot()
for (i in 1:2) {
p <- p + geom_histogram(data=xx[[i]], aes(x= Sepal.Length, stat(density), fill= factor(names(cols)[i])))
p2 <- p2 + geom_histogram(data=xx[[i]], aes(x= Sepal.Length, stat(density), fill= factor(cols[i])))
}
p + scale_fill_manual(values= cols)
p2 + scale_fill_manual(values= cols)
iris <- xx[[1]]
iris2 <- xx[[2]]
p3 <- ggplot() +
geom_histogram(data= iris, aes(x= Sepal.Length, stat(density), fill= factor("low"))) +
geom_histogram(data= iris2, aes(x= Sepal.Length, stat(density), fill= factor("high"))) +
scale_fill_manual(values= cols)
p3





Это не способ ggplot.
Вместо этого рассмотрите возможность сделать следующее
data(iris)
xx <- list(iris, iris)
xx[[1]]$Sepal.Length <- rnorm(150)
xx[[2]]$Sepal.Length <- rnorm(150,mean = 10)
cols <- c("low" = "#e41a1c", "high"= "#377eb8")
names(xx) <- names(cols)
library(tidyverse)
bind_rows(xx, .id = "Key") %>%
ggplot(aes(Sepal.Length, fill = Key)) +
geom_histogram()
Объяснение: Мы связываем data.frame в ряд в list, сохраняя имя элемента list в Key. Затем у нас есть один data.frame, и мы используем эстетику fill для сопоставления разных Key с разными заливками.
Моя гипотеза заключалась в том, что стек вызовов вычисляется лениво. То есть отображение заливки на names(cols)[i] без вычисления этого выражения. Следовательно, отображение идентично в scale_fill_manual.
В конечном итоге это верно. Как отмечает @maurits выше, ggplot2 не предназначен для этого варианта использования. Ниже работает
# @description Process a set of input data.frame's to extract only the
# column of interest and assign a group name
dtlist_inputs <- function(dt_list, varname, groups, input= TRUE) {
dt_list <- do.call('rbind', (mapply(function(l, groupname, varname) {
return(data.frame(
group= groupname
, var= get(varname, as.environment(l))
))
}, l= dt_list, groupname= groups, varname= varname, SIMPLIFY= FALSE)))
return(dt_list)
}
# @description Histogram for multiple groups, where each group is input as a separate data.frame.
# @param dt_list a \code{list} of \code{data.frame}s
# @param cols a named vector of colour hexes.
# @varname A \code{character} scalar denoting the variable in each element of \code{dt_list} you wish to plot.
# @binwidth To be passed to `\code{\link[ggplot2]{geom_histogram}}.
# @x_lab To be passed to `\code{\link[ggplot2]{labs}}.
# @grouptitle To be passed to `\code{\link[ggplot2]{guides}} for legend label.
# @x_breaks To be passed to `\code{\link[ggplot2]{scale_x_continuous}} for axis breaks.
GGgroup_histogram <- function(dt_list, cols, varname, binwidth= 0.02,
grouptitle= "Error Group",
x_lab= "Variable", x_breaks= seq(0,1,.1)) {
if (length(dt_list) != length(cols)) stop("length of dt_list and cols must match.")
dt_list <- dtlist_inputs(dt_list, varname, groups= names(cols))
sub_title <- paste("Variable:", varname)
p <- ggplot() +
geom_histogram(data= dt_list, aes(x=var, stat(density), fill= factor(group)),
binwidth= binwidth, alpha= 0.5)
p <- p + labs(y= "Density", x= x_lab,
title= "Distributional differences in relative abs error between groups",
subtitle= sub_title) +
scale_fill_manual(values= cols) +
scale_x_continuous(breaks= x_breaks) +
guides(fill= guide_legend(title= grouptitle)) +
theme(legend.position = "bottom",
axis.title= element_text(face= "bold", size= 11),
axis.text= element_text(size= 10),
plot.title= element_text(face= "bold.italic", size= 13),
plot.subtitle= element_text(face= "bold.italic", size= 12))
return(p)
}
Редактировать Мы также можем сравнить идею использования dplyr::bind_rows (предложенную выше) с моей естественной склонностью предпочитать data.table::rbindlist:
set.seed(6231)
d <- data.frame(x1= rnorm(1000), x2= rnorm(1000), x3= rnorm(100))
d <- replicate(n= 10, expr= d, simplify = FALSE)
library(microbenchmark)
microbenchmark(
base= do.call('rbind', d),
dplyr= dplyr::bind_rows(d),
data.table= data.table::rbindlist(d)
)
Unit: microseconds
expr min lq mean median uq max neval cld
base 697.373 783.108 2484.0814 842.7745 923.9245 121350.787 100 a
dplyr 161.385 186.140 279.2899 211.4355 229.4350 3488.347 100 a
data.table 108.853 137.612 247.6596 159.0105 181.3150 5874.138 100 a
## with replicate(... n= 1000)
Unit: milliseconds
expr min lq mean median uq max neval cld
base 211.718863 480.355404 707.60993 722.989094 948.77399 1020.6656 100 b
dplyr 16.597688 18.184643 72.09627 21.374848 25.19133 293.0039 100 a
data.table 3.122027 3.480451 49.24004 6.545908 9.54836 270.4440 100 a
Это ожидаемое поведение.
aes(x= Sepal.Length, stat(density), fill= factor(cols[i]))будет удерживать выражениеfactor(cols[i])и оценивать его до тех пор, пока выражение не понадобится. В вашем случае это две строки после цикла for, гдеi == 2