2017-07-25 12 views
5

Przygotowuję mapę, w której chcę umieścić małą etykietkę tekstową w każdym stanie. Mój obecny problem jest, że tekst wykracza poza granice państwowe, więc nie wyglądają ładnie: enter image description hereJak upewnić się, że tytuł tekstu znajduje się wewnątrz obiektu wielokąta?

Próbowałem za pomocą średnia, mediana, centroidy i tak dalej.

Co chcę jest każdy tekst całkowicie znajdować się wewnątrz lub na zewnątrz wielokąta, jak tutaj: enter image description here (obraz z http://www.businessinsider.com/map-what-100-is-actually-worth-in-your-state-2015-7?IR=T)

używam następujący kod do generowania mój obrazek:

library(maps) 
library(dplyr) 
library(ggplot2) 

#data 
mapbase <- map_data("state.vbm")  
data(state.vbm.center) 
df <- state.vbm.center %>% as.data.frame() %>% 
    mutate(region = unique(mapbase$region)) %>% full_join(mapbase) 


#actual plotting 
cnames <- aggregate(cbind(long, lat) ~ region, data=df, FUN=median) 
gmap<- 
    ggplot()+ 
    geom_polygon(data=df2, 
       aes(long, lat, group = region, fill = somevalue,alpha=0.3)) + 
    coord_fixed() + 
    theme_void() + 
    geom_text(data=cnames, aes(fontface=2 ,cnames$long, cnames$lat , label = "text" 
), color= "black" ,size=3,check_overlap = T, position=position_jitter(width=3, height=3) ) + 

    scale_fill_gradient(low="red",high="blue") 

Dziękuję bardzo za wskazówki!

Odpowiedz

3

Kilka punktów do rozważenia.

1 - Optymalne miejsce dla celów adnotacji wewnątrz wielokąta

w idealnym świecie, każdy wielokąt jest podobna do okręgu, a jej centrum jest najlepszym miejscem, aby umieścić etykietę tekstową (np Teksas). W rzeczywistości regiony map są w różnych kształtach, & może nawet nie być w jednym kawałku (np. Michigan). Średnia matematyczna/mediana może znajdować się na krawędzi lub poza poligonem (na przykład na Florydzie).

R nie będzie tak wielki, próbując zrozumieć te komplikacje. Zamiast tego użyłbym oprogramowania GIS.

Jeśli jednak Twój przypadek użycia to USA, zestaw danych state.vbm.center ma już całkiem niezły zestaw domyślnych współrzędnych. Jej stany plików pomocy:

state.vbm.center są współrzędne ośrodkach państwowych dla adnotacji celów.

Rzućmy okiem na których te punkty to:

#data 
mapbase <- map_data("state.vbm")  
data(state.vbm.center) 

cnames <- state.vbm.center %>% as.data.frame() %>% 
    mutate(region = unique(mapbase$region)) 

#actual plotting 
ggplot()+ 
    geom_polygon(data=mapbase, 
       aes(long, lat, group = region, fill = region), 
       alpha = 0.3) + 
    coord_fixed() + theme_void() + 
    geom_point(data = cnames, 
      aes(x, y)) + 
    scale_fill_discrete(guide = F) 

center location

to nie jest zbyt brudny. Jeśli wszystko, co potrzebne do znakowania są nazwy stanów, to powinno wystarczyć:

cnames$abb <- state.abb 

ggplot()+ 
    geom_polygon(data=mapbase, 
       aes(long, lat, group = region, fill = region), 
       alpha = 0.3) + 
    coord_fixed() + theme_void() + 
    geom_text(data=cnames, 
      aes(x, y , label = abb), 
      color= "black", size=3, fontface = 2, 
      hjust = 0.5, vjust = 0.5) + #central alignment 
    scale_fill_discrete(guide = F) 

abbreviated names

2 - Montaż długich etykiet w ciasnych przestrzeniach

To bardzo dobrze przylegające krótkie etykiety zasięgu map wielokątów, ale jeśli chcesz podać więcej informacji (pełna nazwa każdego stanu, wskaźnik urodzeń, wskaźnik przestępczości, stopa bezrobocia, poziom wykształcenia, zasięg dochodów, gęstość zaludnienia, odsetek osób, które głosowały w ostatnich wyborach, ...), ostatecznie zaczną brakować miejsca w mniejszych/więcej wei Wieloboki w kształcie rdly.

W tym miejscu można przyjąć podejście podwójne, zachowując informacje w obrębie większych wielokątów, & umieszczając mniejsze wielokąty oddzielnie po jednej stronie, jak w częściowej legendzie. Dla stanów USA, strefa stan jest częścią standardowego datasets pakietu, co oszczędza nam kłopotu z jej obliczenia:

# incorporate area information & identify small area states 
cnames$area <- state.area 
ggplot(cnames %>% 
     mutate(region = factor(region, levels = region[order(area)])), 
     aes(x = region, y = area)) + geom_col() + 
    theme_classic() + 
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) 

# the first 7 states (up to Maryland) are noticeably smaller than the rest 

sorted by area size

Wybierz jakieś fajne pusty obszar na mapę dla małych państw. I postanowił dostosować je pionowo w 1 kolumnie na długości = 140 & szerokość w zakresie od 0 do 60:

library(tidyr) 

legend.states <- cnames$region[which(cnames$area <= 10577)] 
legend.states <- as.data.frame(legend.states) 
legend.states$long1 <- 140 
legend.states$lat1 <- seq(0, 60, length.out = nrow(legend.states)) 
legend.states <- legend.states %>% 
    mutate(long2 = long1 + 5, lat2 = lat1) %>% 
    mutate(long3 = long2, lat3 = lat2 - 5) %>% 
    mutate(long4 = long1, lat4 = lat3) %>% 
    mutate(long5 = long1, lat5 = lat1) %>% 
    gather(k, v, -legend.states) %>% 
    mutate(order = as.integer(substring(k, nchar(k))), 
     k = gsub("[0-9]", "", k)) %>% 
    spread(k, v) %>% 
    rename(region = legend.states) %>% 
    mutate(group = mapbase$group[match(region, mapbase$region)]) %>% 
    select(long, lat, group, order, region) %>% 
    mutate(subregion = NA) 

# add legend polygons to the original polygon dataset 
mapbase2 <- rbind(mapbase, legend.states) 

przekształcenie współrzędnych Adnotacja tych małych stanach, tak że są dostosowane do położeń legendę:

cnames2 <- left_join(cnames, 
        legend.states %>% filter(order %in% c(1, 4)) %>% 
         group_by(region) %>% 
         summarise(long = mean(long) + 7, 
           lat = mean(lat))) %>% 
    mutate(x = coalesce(long, x), 
     y = coalesce(lat, y), 
     hjust = ifelse(is.na(lat), 0.5, 0)) 
# left alignment (hjust=0) for small state text, central alignment (hjust=0.5) otherwise. 

umieścić wszystko razem:

ggplot()+ 
    geom_polygon(data=mapbase2, 
       aes(long, lat, group = region, fill = region), 
       alpha = 0.3) + 
    coord_fixed() + theme_void() + 
    geom_text(data=cnames2, 
      aes(x, y , label = abb, hjust = hjust), 
      size=3, fontface = 2, 
      vjust = 0.5) + 
    scale_fill_discrete(guide = F) 

legend box

(Uwaga: w przypadku dłuższego tekstu prawdopodobnie będziesz musiał również zwiększyć ograniczenia osi X i/lub wstawić znaki linii podziału.)

Powiązane problemy