Построение дискретных и непрерывных масштабов в одном и том же ggplot

Я хотел бы построить несколько разных элементов данных, используя ggplot2, используя две разные цветовые шкалы (один непрерывный и один дискретный из двух разных df). Я могу описать то, что мне хотелось бы по отдельности, но я не могу заставить их работать вместе. Кажется, у вас не может быть двух разных цветовых шкал, работающих на одном и том же участке? Я видел подобные вопросы здесь и здесь, и это привело меня к тому, что я хотел бы достичь просто невозможно в ggplot2, но на случай, если я ошибаюсь, я хотел бы проиллюстрировать свою проблему, чтобы увидеть, есть ли обход.

У меня есть некоторые данные потока ГИС, к которым прикреплены некоторые категориальные атрибуты, которые я могу построить (p1 в коде ниже), чтобы получить: enter image description here

У меня также есть набор местоположений, которые имеют непрерывный отклик, который я также могу построить (p2 в коде ниже), чтобы получить: enter image description here Однако я не могу объединить два (p3 в коде ниже). Я получаю эту ошибку

Ошибка в масштабах [[prev_aes]]: попытка выбрать менее одного элемента

Замечание строки scale_colour_hue("Strahler order") + изменяет ошибку на

Ошибка: дискретное значение, подаваемое на непрерывный масштаб

Похоже, что ggplot2 использует один и тот же тип шкалы (непрерывный или дискретный) для вызова geom_path и вызовов geom_point. Поэтому, когда я передаю дискретную переменную factor(Strahler), в шкалу scale_colour_gradientn, график не выполняется.

Есть ли способ обойти это? Было бы удивительно, если бы был аргумент data функции масштабирования, чтобы сообщить ему, где он должен отображать или устанавливать атрибуты. Возможно ли это?

Большое спасибо и воспроизводимый код ниже:

library(ggplot2)

### Download df   ###
oldwd <- getwd(); tmp <- tempdir(); setwd(tmp)
url <- "http://dl.dropbox.com/u/44829974/Data.zip"
f <- paste(tmp,"\\tmp.zip",sep="")
download.file(url,f)
unzip(f)


### Read in data    ###
riv_df <- read.table("riv_df.csv", sep=",",h=T)
afr_df <- read.table("afr_df.csv", sep=",",h=T)
vil_df <- read.table("vil_df.csv", sep=",",h=T)


### Min and max for plot area   ###
xmin <- -18; xmax <- 3; ymin <- 4; ymax <- 15


### Plot river data ###
p1 <-   ggplot(riv_df, aes(long, lat)) + 
    geom_map( mapping = aes( long , lat , map_id = id ) , fill = "white" , data = afr_df , map = afr_df ) +
    geom_path( colour = "grey95" , mapping = aes( long , lat , group = group , size = 1 ) , data = afr_df ) +
    geom_path( aes( group = id , alpha = I(Strahler/6) , colour = factor(Strahler) , size = Strahler/6 ) ) +
    scale_alpha( guide = "none" ) +
    scale_colour_hue("Strahler order") +
    scale_x_continuous( limits = c( xmin , xmax ) , expand = c( 0 , 0 ) ) +
    scale_y_continuous( limits = c( ymin , ymax ) , expand = c( 0 , 0 ) ) +
    coord_map()
print(p1) # This may take a little while depending on computer speed...



### Plot response data  ###
p2 <- ggplot( NULL ) +
    geom_point( aes( X , Y , colour = Z) , size = 2 , shape = 19 , data = vil_df ) +
    scale_colour_gradientn( colours = rev(heat.colors(25)) , guide="colourbar" ) +
    coord_equal()
print(p2)



### Plot both together  ###
p3 <-   ggplot(riv_df, aes(long, lat)) + 
    geom_map( mapping = aes( long , lat , map_id = id ) , fill = "white" , data = afr_df , map = afr_df ) +
    geom_path( colour = "grey95" , mapping = aes( long , lat , group = group , size = 1 ) , data = afr_df ) +
    geom_path( aes( group = id , alpha = I(Strahler/6) , colour = factor(Strahler) , size = Strahler/6 ) ) +
    scale_colour_hue("Strahler order") +
    scale_alpha( guide = "none" ) +
    scale_x_continuous( limits = c( xmin , xmax ) , expand = c( 0 , 0 ) ) +
    scale_y_continuous( limits = c( ymin , ymax ) , expand = c( 0 , 0 ) ) +
    geom_point( aes( X , Y , colour = Z) , size = 2 , shape = 19 , data = vil_df ) +
    scale_colour_gradientn( colours = rev(heat.colors(25)) , guide="colourbar" ) +
    coord_map()
print(p3)
#Error in scales[[prev_aes]] : attempt to select less than one element

### Clear-up downloaded files   ###
unlink(tmp,recursive=T)
setwd(oldwd)

Приветствия,

Саймон

Ответ 1

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

Однако, я думал, что некоторым людям может понравиться указатель на то, как добиться этого. Нотабене Я использовал код из этого gist, чтобы сделать элементы в верхнем графике прозрачными, чтобы они не замаскировали элементы ниже:

grid.newpage()
pushViewport( viewport( layout = grid.layout( 1 , 1 , widths = unit( 1 , "npc" ) ) ) ) 
print( p1 + theme(legend.position="none") , vp = viewport( layout.pos.row = 1 , layout.pos.col = 1 ) )
print( p2 + theme(legend.position="none") , vp = viewport( layout.pos.row = 1 , layout.pos.col = 1 ) )

См. мой ответ здесь, чтобы добавить легенды в другую позицию в макете сетки.

enter image description here

Ответ 2

Проблема не такая сложная, как вы думаете. В общем, вы можете только один раз отобразить эстетику. Поэтому вызов scale_colour_* дважды не имеет смысла для ggplot2. Он попытается принудить одного к другому.

Вы не можете иметь несколько цветовых шкал на одном графике, независимо от того, является ли он непрерывным или дискретным. Автор пакета сказал, что они также не собираются добавлять это. Это довольно сложно реализовать, и было бы слишком легко сделать невероятно запутывающие графики. (Несколько осей y никогда не будут реализованы по тем же причинам.)

Ответ 3

На данный момент у меня нет времени, чтобы представить полный рабочий пример, но есть еще один способ сделать это, который заслуживает упоминания здесь: Заполнить цвет и границу в geom_point (scale_colour_manual) в ggplot

В принципе, использование geom_point в сочетании с shape = 21, color = NA позволяет вам управлять цветом ряда точек, используя эстетику fill, а не color. Вот как выглядел мой код. Я понимаю, что нет данных, но, надеюсь, он дает вам исходную точку:

biloxi + 
  geom_point(data = filter(train, primary != 'na'), 
             aes(y = GEO_LATITUDE, x = GEO_LONGITUDE, fill = primary), 
             shape = 21, color = NA, size = 1) + 
    scale_fill_manual(values = c('dodgerblue', 'firebrick')) + 
  geom_point(data = test_map_frame, 
             aes(y = GEO_LATITUDE, x = GEO_LONGITUDE, color = var_score), 
            alpha = 1, size = 1) + 
    scale_color_gradient2(low = 'dodgerblue4', high = 'firebrick4', mid = 'white',
                    midpoint = mean(test_map_frame$var_score))   

Обратите внимание, что каждый вызов geom_point вызывает другую эстетику (color или fill)