2014-12-23 8 views
9

C'è un modo per mantenere i punti che sono agitati su una mappa all'interno di un confine di quella mappa? Nell'esempio qui sotto, dove le posizioni nervose nel Connecticut sud-occidentale finiscono in acqua o in uno stato adiacente, c'è un modo per avere R jitter i punti di localizzazione ma non oltre il limite di una mappa?In che modo ggplot2 può mantenere posizioni distorte all'interno di un limite della mappa, ad esempio uno stato USA?

In alternativa, c'è qualche altra tecnica, come quella di creare un tavolo grob vicino a ciascuna città per elencare i nomi delle imprese?

# create a data frame called "ct" of geolocations in two cities near the border of a US state (Connecticut). Each firm has the same lat and longitude of one of the two cities 

> dput(ct) 
structure(list(city = structure(c(1L, 1L, 1L, 1L, 1L, 2L, 2L, 
2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 2L, 
2L, 2L, 2L, 2L), .Label = c("Greenwich", "Stamford"), class = "factor"), 
    firm = structure(c(1L, 12L, 21L, 22L, 23L, 24L, 25L, 26L, 
    27L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L, 11L, 13L, 14L, 
    15L, 16L, 17L, 18L, 19L, 20L), .Label = c("A1", "A10", "A11", 
    "A12", "A13", "A14", "A15", "A16", "A17", "A18", "A19", "A2", 
    "A20", "A21", "A22", "A23", "A24", "A25", "A26", "A27", "A3", 
    "A4", "A5", "A6", "A7", "A8", "A9"), class = "factor"), long = c(-73.63, 
    -73.63, -73.63, -73.63, -73.63, -73.55, -73.55, -73.55, -73.55, 
    -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, 
    -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, -73.55, 
    -73.55, -73.55), lat = c(41.06, 41.06, 41.06, 41.06, 41.06, 
    41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 
    41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 41.09, 
    41.09, 41.09, 41.09, 41.09)), .Names = c("city", "firm", 
"long", "lat"), row.names = c(NA, -27L), class = "data.frame") 


library(ggplot2) 
# load the map of the United States 
all_states <- map_data("state") 
# choose to map the borders only of the state of Connecticut 
st.map <- subset(all_states, region == "connecticut") 

# plot the points for the firms with minimal jitter that still distinguishes each point 
ggplot(ct, aes(long, lat)) + 
    geom_polygon(data=st.map, aes(x=long, y=lat, group = group), colour="grey70", fill="white") + 
    coord_map() + 
    geom_point(position=position_jitter(width=.1, height=.1), size=2) 

enter image description here

Cambiare ogni longitudine o latitudine un po 'piccolo, come in questa domanda, non funzionerà, perché ci sono troppi punti e spero in una soluzione algoritmica, dal momento che ho molte situazioni dove potrebbe sorgere questo affollamento e il passaggio di confine. https://stackoverflow.com/questions/22943110/jitter-coordinates

Grazie per eventuali suggerimenti o risposte.

risposta

7

È possibile creare la propria funzione jitter che agita i dati. Quindi utilizzare la funzione pnt.in.poly da SDMTools per verificare se il punto si trova all'interno del poligono. Altrimenti si agita nuovamente il punto originale. Vedi sotto per un esempio:

require(SDMTools) 
bounded_jitter <- function(mapping, data, bounds, width, height, ...){ 
    # data2 is the jittered data 
    data2 <- data 
    data2[, paste(mapping$x)] <- rnorm(nrow(data), data[, paste(mapping$x)], width/1.96) 
    data2[, paste(mapping$y)] <- rnorm(nrow(data), data[, paste(mapping$y)], height/1.96) 
    # is it inside the polygon? 
    idx <- as.logical(pnt.in.poly(pnts = data2[, c(paste(mapping$x), paste(mapping$y))], 
           poly.pnts = bounds)[, 'pip']) 
    while(!all(idx)) { # redo for points outside polygon 
    data2[!idx, paste(mapping$x)] <- rnorm(sum(!idx), data[!idx, paste(mapping$x)], width/1.96) 
    data2[!idx, paste(mapping$y)] <- rnorm(sum(!idx), data[!idx, paste(mapping$y)], height/1.96) 
    idx <- as.logical(pnt.in.poly(pnts = data2[, c(paste(mapping$x), paste(mapping$y))], 
            poly.pnts = bounds)[, 'pip']) 
    } 
    # the point 
    geom_point(data = data2, mapping, ...) 
} 
# plot the points for the firms with minimal jitter that still distinguishes each point 
ggplot(ct, aes(long, lat)) + 
    geom_polygon(data=st.map, aes(x=long, y=lat, group = group), colour="grey70", fill="white") + 
    coord_map() + 
    geom_point(size=2) + 
    bounded_jitter(mapping = aes(x=long, y=lat), 
       data = ct, 
       bounds = st.map[, c('long', 'lat')], 
       width = .1, 
       height = .1) 

resulting plot: Connecticut with jittered points inside

+0

Wow, questa è una grande funzione. Sarebbe bello se questa funzione esistesse in un pacchetto! +1 – jazzurro

+0

@shadow, è molto bello! Che cosa succede se ho questa situazione in molti stati e non so quali saranno i nervosismi? I miei casi d'uso reali hanno migliaia di posizioni in centinaia di città, molte delle quali sono vicine a oceani, laghi o linee di stato. Come posso avere R controllo per il passaggio di confine e chiamare la funzione quando necessario? – lawyeR