如何确保文本标题位于多边形对象内?

时间:2017-07-25 10:30:59

标签: r ggplot2 visualization matplotlib-basemap

我正在制作地图,我想在每个州内放置一个小文字标签。我目前的问题是文本超出了州限制,所以看起来不太好看: enter image description here

我尝试使用均值,中位数,质心等。

我想要的是每个文字完全在多边形内部或外部,例如:enter image description here(来自http://www.businessinsider.com/map-what-100-is-actually-worth-in-your-state-2015-7?IR=T的图片)

我使用以下代码生成我的图片:

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")

非常感谢你的提示!

1 个答案:

答案 0 :(得分:5)

需要考虑几点。

1 - 多边形内注释的最佳位置

在理想世界中,每个多边形都类似于圆形,其中心是定位文本标签(例如德克萨斯州)的最佳位置。实际上,地图区域有各种各样的形状,&amp;可能甚至不是一个整体(例如密歇根州)。数学平均值/中值点可以在多边形的边缘或外部(例如佛罗里达)。

在尝试找出这些并发症时,R不会那么出色。我改用GIS软件。

但是,如果您的用例是美国,则state.vbm.center数据集已经附带了一组非常好的默认坐标。其帮助文件指出:

  

state.vbm.center是状态中心的坐标用于注释   的目的

让我们来看看这些观点的位置:

#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

那不是太破旧。如果你需要标记的只是州名,那就足够了:

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 - 将长标签装入狭小空间

它非常适合地图多边形中的短标签,但如果您想要包含更多信息(每个州的全名,出生率,犯罪率,失业率,教育水平,收入范围,人口密度,在上次选举中投票的人的比例,...),最终你会在较小/更奇怪形状的多边形中开始用尽空间。

此时可采用双重方法,将信息保持在较大的多边形内,并且将较小的多边形分开放置在一侧,就像部分图例一样。对于美国州,州地区是标准datasets包的一部分,这使我们省去了计算它的麻烦:

# 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

在地图上为小州选择一些漂亮的空白区域。我决定将它们垂直对齐在1列,经度= 140,&amp;纬度范围从0到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)

更改这些小状态的注释坐标,使它们与图例框位置对齐:

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.

把所有东西放在一起:

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

(注意:对于较长的文本,您可能还需要增加x轴限制,和/或插入换行符。)