Обоснование нескольких легенд в ggmap/ggplot2

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

require(ggplot2)
require(ggmap)
require(grid)
require(mapproj)

data <- data.frame(Org=rep(c("ABCDEFG","HIJKLMNOP","QRSTUVWX"),4)
                   , Type=rep(c("Y","Z"),6), Lat=runif(12,48,54.5)
                   , Long=runif(12,-133.5,-122.5))

osmMap <- get_map(location=c(-134,47.5,-122,55), source = 'osm')

points <- geom_jitter(data=data, aes(Long, Lat, shape=Type
                                     , colour=Org))

legend <- theme(legend.justification=c(0,0), legend.position=c(0,0)
                , legend.margin=unit(0,"lines"), legend.box="vertical"
                , legend.key.size=unit(1,"lines"), legend.text.align=0
                , legend.title.align=0)

ggmap(osmMap) + points + legend

введите здесь описание изображения


person andyteucher    schedule 17.11.2012    source источник
comment
Это не прямой ответ, но вы можете немного схитрить, используя формат, чтобы сделать их одинакового размера. Попробуйте data$Type <- format(data$Type, width=17) после объявления данных и перезапустите код.   -  person Brandon Bertelsen    schedule 17.11.2012
comment
Это ловкий трюк, спасибо. попробую в понедельник   -  person andyteucher    schedule 17.11.2012


Ответы (1)


Эта опция теперь доступна в ggplot2 0.9.3.1, используйте

ggmap(osmMap) + points + legend + theme(legend.box.just = "left")

Старое ручное решение:

Вот решение:

require(gtable)
require(ggplot2)
require(ggmap)
require(grid)
require(mapproj)

# Original data
data <- data.frame(Org=rep(c("ABCDEFG","HIJKLMNOP","QRSTUVWX"),4),
                   Type=rep(c("Y","Z"),6), Lat=runif(12,48,54.5),
                   Long=runif(12,-133.5,-122.5))
osmMap <- get_map(location=c(-134,47.5,-122,55), source = 'google')
points <- geom_jitter(data=data, aes(Long, Lat, shape=Type, colour=Org))
legend <- theme(legend.justification=c(0,0), legend.position=c(0,0),
                legend.margin=unit(0,"lines"), legend.box="vertical",
                legend.key.size=unit(1,"lines"), legend.text.align=0,
                legend.title.align=0)

# Data transformation
p <- ggmap(osmMap) + points + legend
data <- ggplot_build(p)
gtable <- ggplot_gtable(data)

# Determining index of legends table
lbox <- which(sapply(gtable$grobs, paste) == "gtable[guide-box]")
# Each legend has several parts, wdth contains total widths for each legend
wdth <- with(gtable$grobs[[lbox]], c(sum(as.vector(grobs[[1]]$widths)), 
                                     sum(as.vector(grobs[[2]]$widths))))
# Determining narrower legend
id <- which.min(wdth)
# Adding a new empty column of abs(diff(wdth)) mm width on the right of 
# the smaller legend box
gtable$grobs[[lbox]]$grobs[[id]] <- gtable_add_cols(
                                      gtable$grobs[[lbox]]$grobs[[id]], 
                                      unit(abs(diff(wdth)), "mm"))
# Plotting
grid.draw(gtable)

Это не зависит от Type или Org. Однако этого было бы недостаточно, если бы было больше двух легенд. Кроме того, если вы вносите какие-либо изменения, чтобы изменить список grobs (графических объектов), вам может потребоваться изменить grobs[[8]] на grobs[[i]], где i — положение ваших легенд, см. gtable$grobs и найдите TableGrob (5 x 3) "guide-box": 2 grobs. введите здесь описание изображения

Редактировать: 1. Автоматическое определение того, какой grob является таблицей легенд, т.е. нет необходимости что-либо менять после изменения других частей графика. 2. Изменен расчет разницы ширины, теперь код должен работать при наличии любых двух легенд, т.е. и в более сложных случаях, например:

введите здесь описание изображения

person Julius Vainora    schedule 18.11.2012
comment
Спасибо @Julius - это хорошо работает и дало мне некоторое представление об использовании gtable, которое я раньше не изучал. - person andyteucher; 19.11.2012
comment
Я не могу воспроизвести этот пример. Откуда я могу получить osmMap? Я предполагаю, что это некоторый набор данных. - person Faheem Mitha; 09.04.2013
comment
@FaheemMitha, да, это данные из вопроса. Я добавил его в свой ответ, а также изменил source = 'osm' на source = 'google', поскольку первый не работает, по крайней мере, на данный момент. - person Julius Vainora; 09.04.2013
comment
Спасибо, Юлий. Я ценю быстрый ответ. - person Faheem Mitha; 10.04.2013