ggplot 创建带箭头的地图
ggplot create map with arrows
我有这样一个数据框
id lon lat
1 A -69.5 -58.5
2 A -69.5 -58.5
3 A -69.5 -57.5
4 A -68.5 -57.5
5 A -68.5 -57.5
6 A -68.5 -57.5
7 A -66.5 -57.5
8 A -68.5 -56.5
9 A -68.5 -56.5
10 A -67.5 -56.5
11 A -65.5 -56.5
12 A -65.5 -56.5
13 A -65.5 -55.5
14 A -62.5 -54.5
15 B -177 -52.5
16 B -178 -50.5
17 B -179 -48.5
18 B 179 -47.5
19 B 178 -46.5
20 B 177 -46.5
我想制作一张 A 和 B 位置的地图,由定向线连接。然而,当 ids 穿过太平洋时(lon=-180 -> lon=+180),我得到一个穿过整个图形的箭头,如下所示。
这是我正在使用的代码
worldmap = map_data("world")
ggplot(test, aes(x = lon, y=lat, colour = factor(id))) +
geom_polygon(data=worldmap,center=180,aes(x=long, y=lat, group=group), fill="black",colour="black") +
xlab("") +ylab("")+theme(axis.text=element_blank(),axis.ticks=element_blank())+ theme(panel.background = element_rect(fill = 'white', colour = 'black') ,panel.grid.major = element_blank(),panel.grid.minor = element_blank())+
geom_path(size =2,arrow = arrow(angle=30,length = unit(0.6, "inches")))
我该如何解决?
谢谢
我想这取决于您认为 "right" 想做什么。我决定通过在地图边缘添加点,然后创建一个 "sequence" 指示器,以便 ggplot 知道要连接哪些线,将穿过 glob 的路径分成两段。这是您的示例数据的转换
test2 <- do.call(rbind, lapply(split(test, test$id), function(x) {
cp <- cumsum(c(FALSE, diff(x$lon)>250))
xx<-split(x, cp)
xx<-Map(cbind, xx, seq=seq_along(xx))
Reduce(function(a,b) {
lasta<-a[nrow(a),]
firstb<-b[1,]
lasta$lon <- 180*sign(lasta$lon)
firstb$lon <- 180*sign(firstb$lon)
lasta$lat <- mean(lasta$lat, firstb$lat)
firstb$lat <- lasta$lat
rbind(a,lasta, firstb,b)
}, xx)
}))
tail(test2)
# id lon lat seq
# B.17 B -179 -48.5 1
# B.171 B -180 -48.5 1
# B.18 B 180 -48.5 2
# B.181 B 179 -47.5 2
# B.19 B 178 -46.5 2
# B.20 B 177 -46.5 2
在这里您可以看到我们将 B 行分成了两个序列。那如果我们用组审美
geom_path(aes(group=interaction(id, seq)), ...)
那么 R 将只连接属于同一 id/seq 组的那些点。这将防止线路越过海洋。但是,因为我们为该组绘制了两条线而不是一条线,所以无法只为其中一个线段转动箭头。您可能想找到另一种方式来指示 start/end.
我有这样一个数据框
id lon lat
1 A -69.5 -58.5
2 A -69.5 -58.5
3 A -69.5 -57.5
4 A -68.5 -57.5
5 A -68.5 -57.5
6 A -68.5 -57.5
7 A -66.5 -57.5
8 A -68.5 -56.5
9 A -68.5 -56.5
10 A -67.5 -56.5
11 A -65.5 -56.5
12 A -65.5 -56.5
13 A -65.5 -55.5
14 A -62.5 -54.5
15 B -177 -52.5
16 B -178 -50.5
17 B -179 -48.5
18 B 179 -47.5
19 B 178 -46.5
20 B 177 -46.5
我想制作一张 A 和 B 位置的地图,由定向线连接。然而,当 ids 穿过太平洋时(lon=-180 -> lon=+180),我得到一个穿过整个图形的箭头,如下所示。
这是我正在使用的代码
worldmap = map_data("world")
ggplot(test, aes(x = lon, y=lat, colour = factor(id))) +
geom_polygon(data=worldmap,center=180,aes(x=long, y=lat, group=group), fill="black",colour="black") +
xlab("") +ylab("")+theme(axis.text=element_blank(),axis.ticks=element_blank())+ theme(panel.background = element_rect(fill = 'white', colour = 'black') ,panel.grid.major = element_blank(),panel.grid.minor = element_blank())+
geom_path(size =2,arrow = arrow(angle=30,length = unit(0.6, "inches")))
我该如何解决?
谢谢
我想这取决于您认为 "right" 想做什么。我决定通过在地图边缘添加点,然后创建一个 "sequence" 指示器,以便 ggplot 知道要连接哪些线,将穿过 glob 的路径分成两段。这是您的示例数据的转换
test2 <- do.call(rbind, lapply(split(test, test$id), function(x) {
cp <- cumsum(c(FALSE, diff(x$lon)>250))
xx<-split(x, cp)
xx<-Map(cbind, xx, seq=seq_along(xx))
Reduce(function(a,b) {
lasta<-a[nrow(a),]
firstb<-b[1,]
lasta$lon <- 180*sign(lasta$lon)
firstb$lon <- 180*sign(firstb$lon)
lasta$lat <- mean(lasta$lat, firstb$lat)
firstb$lat <- lasta$lat
rbind(a,lasta, firstb,b)
}, xx)
}))
tail(test2)
# id lon lat seq
# B.17 B -179 -48.5 1
# B.171 B -180 -48.5 1
# B.18 B 180 -48.5 2
# B.181 B 179 -47.5 2
# B.19 B 178 -46.5 2
# B.20 B 177 -46.5 2
在这里您可以看到我们将 B 行分成了两个序列。那如果我们用组审美
geom_path(aes(group=interaction(id, seq)), ...)
那么 R 将只连接属于同一 id/seq 组的那些点。这将防止线路越过海洋。但是,因为我们为该组绘制了两条线而不是一条线,所以无法只为其中一个线段转动箭头。您可能想找到另一种方式来指示 start/end.