如何确保文本标题在多边形 object 内?
How to make sure text title is inside the polygon object?
我正在制作地图,我想在每个州内放置一个小文本标签。我目前的问题是 文本超出了州限制 ,所以看起来不太好:
我尝试使用均值、中位数、质心等。
我想要的是每个文本都完全在多边形内部或外部,就像这里: (image from 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 - 多边形内进行注释的最佳位置
在理想世界中,每个多边形都类似于一个圆,其中心是放置文本标签的最佳位置(例如德克萨斯州)。实际上,地图区域有各种形状,甚至可能不是一块(例如密歇根州)。数学平均值/中值点可能位于多边形的边缘或外部(例如佛罗里达)。
R 在尝试解决这些并发症方面不会那么出色。我会改用 GIS 软件。
但是,如果您的用例是美国,state.vbm.center
数据集已经带有一组非常好的默认坐标。它的帮助文件指出:
state.vbm.center are coordinates of the state centers for annotation
purposes.
让我们看看这些点在哪里:
#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)
这还不算太寒酸。如果您只需要标记州名,这就足够了:
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)
2 - 将长标签装入紧 spaces
它非常适合地图多边形内的短标签,但如果您想包含更多信息(每个州的全名、出生率、犯罪率、失业率、教育水平、收入范围、人口密度、人口比例在上次选举中投票的人,...),最终你会开始 运行 出 space 在更小/更奇怪形状的多边形中。
此时可以采用双重方法,将信息保留在较大的多边形内,并将较小的多边形单独放置在一侧,如部分图例。对于美国各州,州面积是标准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
在地图上为小州选择一些漂亮的空白区域。我决定将它们在经度 = 140 和纬度范围为 0 到 60 的 1 列中垂直对齐:
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)
(注意:对于较长的文本,您可能还需要增加 x 轴限制,and/or 插入换行符。)
我正在制作地图,我想在每个州内放置一个小文本标签。我目前的问题是 文本超出了州限制 ,所以看起来不太好:
我尝试使用均值、中位数、质心等。
我想要的是每个文本都完全在多边形内部或外部,就像这里:
我使用以下代码生成我的图片:
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 - 多边形内进行注释的最佳位置
在理想世界中,每个多边形都类似于一个圆,其中心是放置文本标签的最佳位置(例如德克萨斯州)。实际上,地图区域有各种形状,甚至可能不是一块(例如密歇根州)。数学平均值/中值点可能位于多边形的边缘或外部(例如佛罗里达)。
R 在尝试解决这些并发症方面不会那么出色。我会改用 GIS 软件。
但是,如果您的用例是美国,state.vbm.center
数据集已经带有一组非常好的默认坐标。它的帮助文件指出:
state.vbm.center are coordinates of the state centers for annotation purposes.
让我们看看这些点在哪里:
#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)
这还不算太寒酸。如果您只需要标记州名,这就足够了:
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)
2 - 将长标签装入紧 spaces
它非常适合地图多边形内的短标签,但如果您想包含更多信息(每个州的全名、出生率、犯罪率、失业率、教育水平、收入范围、人口密度、人口比例在上次选举中投票的人,...),最终你会开始 运行 出 space 在更小/更奇怪形状的多边形中。
此时可以采用双重方法,将信息保留在较大的多边形内,并将较小的多边形单独放置在一侧,如部分图例。对于美国各州,州面积是标准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
在地图上为小州选择一些漂亮的空白区域。我决定将它们在经度 = 140 和纬度范围为 0 到 60 的 1 列中垂直对齐:
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)
(注意:对于较长的文本,您可能还需要增加 x 轴限制,and/or 插入换行符。)