Ggplot2 несколько stat_binhex() графиков с разными цветовыми градиентами на одном изображении

Я хотел бы использовать ggplot2 stat_binhex(), чтобы одновременно отображать две независимые переменные на одной диаграмме, каждая со своим собственным градиентом цвета, используя scale_colour_gradientn().

Если мы проигнорируем тот факт, что единицы оси х не совпадают, воспроизводимым примером будет построение следующего изображения на одном изображении при сохранении отдельных градиентов заполнения.

d <- ggplot(diamonds, aes(x=carat,y=price))+
  stat_binhex(colour="white",na.rm=TRUE)+
  scale_fill_gradientn(colours=c("white","blue"),name = "Frequency",na.value=NA)
try(ggsave(plot=d,filename=<some file>,height=6,width=8))

enter image description here

d <- ggplot(diamonds, aes(x=depth,y=price))+
  stat_binhex(colour="white",na.rm=TRUE)+
  scale_fill_gradientn(colours=c("yellow","black"),name = "Frequency",na.value=NA)
try(ggsave(plot=d,filename=<some other file>,height=6,width=8))

enter image description here

Я нашел некоторую беседу о связанной проблеме в ggplot2 google groups здесь.

Ответ 1

Вот еще одно возможное решение: я взял идею @mnel для сопоставления числа bin с альфа-прозрачностью, и я преобразовал x-переменные, чтобы они могли быть построены на тех же осях.

library(ggplot2)

# Transforms range of data to 0, 1. 
rangeTransform = function(x) (x - min(x)) / (max(x) - min(x))

dat = diamonds
dat$norm_carat = rangeTransform(dat$carat)
dat$norm_depth = rangeTransform(dat$depth)

p1 = ggplot(data=dat) +
     theme_bw() +
     stat_binhex(aes(x=norm_carat, y=price, alpha=..count..), fill="#002BFF") +
     stat_binhex(aes(x=norm_depth, y=price, alpha=..count..), fill="#FFD500") +
     guides(fill=FALSE, alpha=FALSE) +
     xlab("Range Transformed Units")

ggsave(plot=p1, filename="plot_1.png", height=5, width=5)

Мысли:

  • Я попытался (и не смог) отобразить разумную цветовую/альфа-легенду. Кажется сложным, но должно быть возможно, учитывая все функции настройки легенды ggplot2.

  • Маркировка единиц оси X требует своего рода решения. Нанесение двух наборов единиц на одну ось неодобрительно многими, а ggplot2 не имеет такой функции.

  • Интерпретация ячеек с перекрывающимися цветами кажется достаточно очевидной в этом примере, но может быть очень беспорядочной в зависимости от используемых наборов данных и выбранных цветов.

  • Если два цвета являются аддитивными дополнениями, тогда везде, где они будут перекрываться, вы увидите нейтральный серый цвет. Там, где перекрытие неравномерно, серый цвет переместится на более желтый или более синий. Мои цвета не совсем дополняют друг друга, судя по слегка розовому оттенку серого перекрытия.

enter image description here

Ответ 2

Я думаю, что вы хотите идти против принципов ggplot2 и грамматики графического подхода в более общем плане. Пока не будет рассмотрен issue (для которого я бы не задерживал дыхание), у вас есть несколько вариантов

Используйте facet_wrap и alpha

Это не приведет к хорошей легенде, но приведет вас к тому, что вы хотите.

Вы можете установить значение alpha для масштабирования с помощью вычисленного Frequency, доступ к которому осуществляется ..Frequency..

Я не думаю, что вы можете слить легенды, хотя.

library(reshape2)
# in long format
dm <- melt(diamonds, measure.var = c('depth','carat'))

ggplot(dm, aes(y = price, fill = variable, x = value)) + 
   facet_wrap(~variable, ncol = 1, scales  = 'free_x') + 
   stat_binhex(aes(alpha = ..count..), colour = 'grey80') + 
    scale_alpha(name = 'Frequency', range = c(0,1)) + 
    theme_bw() + 
    scale_fill_manual('Variable', values = setNames(c('darkblue','yellow4'), c('depth','carat')))

enter image description here

Используйте gridExtra с помощью grid.arrange или arrangeGrob

Вы можете создать отдельные графики и использовать gridExtra::grid.arrange для размещения на одном изображении.

d_carat <- ggplot(diamonds, aes(x=carat,y=price))+
  stat_binhex(colour="white",na.rm=TRUE)+
  scale_fill_gradientn(colours=c("white","blue"),name = "Frequency",na.value=NA)

d_depth <- ggplot(diamonds, aes(x=depth,y=price))+
  stat_binhex(colour="white",na.rm=TRUE)+
  scale_fill_gradientn(colours=c("yellow","black"),name = "Frequency",na.value=NA)

library(gridExtra)


grid.arrange(d_carat, d_depth, ncol =1)

enter image description here

Если вы хотите, чтобы это работало с ggsave (спасибо @bdemarest комментарий ниже и @baptiste)

замените grid.arrange на arrangeGrob что-то вроде.

ggsave(plot=arrangeGrob(d_carat, d_depth, ncol=1), filename="plot_2.pdf", height=12, width=8)