У меня есть кадр данных в R, в котором несколько столбцов являются факторами. Я хотел бы создать ряд гистограмм, показывающих относительные размеры каждого из уровней фактора. Я хочу связать свои собственные цветовые палитры с каждым из факторов, а затем настроить окончательный макет всех столбцов и легенд с помощью gridExtra.
Я написал пример скрипта, который, как мне кажется, должен этого добиться, однако получил довольно неожиданный результат:
library(ggplot2)
library(grDevices)
library(gridExtra)
# Define some dummy data and put it in a data frame
fruit <- factor(c("apple", "orange", "pear", "pear", "pear",
"orange", "apple", "apple", "apple", "pear"))
cheese <- factor(c("cheddar", "mozarella", "gruyere", "gruyere", "gouda",
"parmesan", "gruyere", "gouda", "mozarella", "cheddar"))
mydata <- data.frame(fruit, cheese)
mydata$dummy <- 0
# Define some custom color schemes
foodclrs <- list()
# Plot the fruit factor in shades of red
h <- c(0.0, 0.0, 0.0)
s <- c(0.95, 0.85, 0.45)
v <- c(0.45, 0.85, 0.95)
foodclrs[[1]] <- hsv(h, s, v)
# Plot the cheese factor in shades of green
h <- c(0.33, 0.33, 0.33, 0.33, 0.33)
s <- c(0.95, 0.93, 0.85, 0.69, 0.45)
v <- c(0.45, 0.69, 0.85, 0.93, 0.95)
foodclrs[[2]] <- hsv(h, s, v)
# Create vectors with individualized text for each plot
bsiz=20
fillvars <- c("fruit", "cheese")
xlabels <- c("Fruits", "Cheeses")
lgdlabels <- c("Types of Fruit", "Types of Cheese")
# Generate a list of plots
plots <- list()
for (ii in 1:2) {
plots[[ii]] <- ggplot(data=mydata) +
geom_bar(aes_string(x="dummy", fill=fillvars[ii]),
position=position_stack(reverse=TRUE)) +
scale_fill_manual(values=foodclrs[[ii]], drop=FALSE) +
theme_bw(base_size=bsiz) +
labs(x=xlabels[ii], y="") +
theme(axis.ticks.y=element_blank(),
axis.text.y=element_blank()) +
guides(fill=guide_legend(title=lgdlabels[ii])) +
coord_flip()
# print(plots[[ii]])
}
# Print the plots on my own custom-shaped grid
print(grid.arrange(plots[[1]], plots[[2]], ncol=1, nrow=2))
Вывод скрипта выглядит следующим образом:
Это не то, чего я ожидал: цветовая палитра для верхней гистограммы должна была представлять собой диапазон оттенков красного. Кажется, что, хотя я изначально определил объект графика plots[[1]]
так, чтобы с ним была связана красная цветовая палитра, когда я действительно пошел его печатать, либо R, либо ggplot2 (я не уверен, что именно) решили использовать самую последнюю цветовую палитру. вместо; то есть тот, который связан с plots[[2]]
.
Теперь вот странная часть. Если я раскомментирую оператор печати в цикле for
, я получу два отдельных графика, которые отображаются в правильной цветовой схеме (для краткости я не буду включать ни один из них здесь), и, что еще более интересно, комбинированную гистограмму. Объект внутри функции grid.arrange()
теперь также отображает правильную цветовую схему:
Хотя я счастлив, что наткнулся на этот небольшой обходной путь, теперь мне любопытно: почему он вообще работает?
Другими словами, как получилось, что вызов оператора «print» в правильный момент внутри цикла for
приводит к тому, что цветовая палитра становится постоянно привязанной к каждому объекту ggplot, в то время как в противном случае этого бы не произошло?
Что на самом деле происходит здесь, так сказать, «под капотом»? А также, есть ли менее неуклюжий способ, которым я мог бы исправить проблему? Например, есть ли какая-то другая функция, которую я мог бы вызвать вместо print()
, чтобы цветовая палитра правильно прикреплялась к каждому объекту графика, не создавая кучу отдельных «фиктивных» графиков, которые мне на самом деле не нужны?
ggplotGrob()
. - person baptiste   schedule 12.09.2017ggplotGrob()
, даже больше, чем мне нравится ваш официальный ответ - это кажется проще и чище, чем инкапсуляция вызова ggplot внутри функции и использование purrr::pmap() для реализации цикла . Тем не менее, я проголосовал за них обоих, поскольку оба пути казались допустимыми решениями. - person stachyra   schedule 12.09.2017