2012-11-17 12 views
16

Ich versuche eine Map mit zwei Legenden zu erstellen, die Form und Farbe bezeichnen ("Type" und "Org" im Beispiel unten) und die Legenden eingefügt haben. Ich kann die Legenden platzieren, aber ich möchte, dass sie linksbündig sind, so dass ihre linken Kanten aneinander liegen. Ich kann ihnen nichts anderes als zentriert in Bezug zueinander machen:Begründung mehrerer Legenden in 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 

enter image description here

+1

Dies ist keine direkte Antwort, aber man kann ein bisschen schummeln indem Sie das Format verwenden, um sie gleich groß zu machen. Versuchen Sie 'data $ Type <- format (data $ Type, width = 17)' nach Ihrer Datendeklaration und führen Sie Ihren Code erneut aus. –

+0

Das ist ein netter Trick, danke. Ich werde es am Montag geben – andyteucher

Antwort

19

Diese Option jetzt in ggplot2 0.9.3.1 verfügbar ist, verwenden

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

Alt, manuelle Lösung:

Hier ist eine Lösung:

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) 

Dies ist unabhängig von Type oder Org. Dies wäre jedoch nicht genug, um mehr als zwei Legenden zu haben. Auch wenn Sie einige Änderungen vornehmen, so dass die Liste der Grobs (Grafikobjekte) geändert wird, müssen Sie möglicherweise grobs[[8]] in grobs[[i]] ändern, wobei i die Position Ihrer Legenden ist, siehe gtable$grobs und suchen Sie nach TableGrob (5 x 3) "guide-box": 2 grobs. enter image description here

Edit: 1. Automatisches Erkennen welche grob ist Legenden Tabelle, das heißt keine Notwendigkeit, etwas zu ändern, nachdem andere Teile des Plots zu modifizieren. 2. Geänderte Berechnung der Breite Unterschiede soll jetzt Code arbeiten, wenn alle zwei Legenden mit, dh in komplexeren Fällen auch, zum Beispiel:

enter image description here

+0

Danke @Julius - das funktioniert gut, und gab mir einige Einblicke in die Verwendung von Gtable, die ich vorher nicht wirklich erforscht hatte. – andyteucher

+0

Ich kann dieses Beispiel nicht reproduzieren. Woher bekomme ich 'osmMap'? Ich nehme an, das ist ein Datensatz. –

+1

@FaheemMitha, ja, das sind Daten aus der Frage. Ich habe es meiner Antwort hinzugefügt und auch 'source = 'osm' zu' source =' google' geändert, da ersteres zumindest nicht funktioniert. – Julius