我将maps
包中的世界地图覆盖到ggplot2
栅格几何体上。但是,此栅格不是以本初子午线(0度)为中心,而是以180度(大致为白令海和太平洋)为中心。以下代码获取地图并以180度重新定位地图:
require(maps)
world_map = data.frame(map(plot=FALSE)[c("x","y")])
names(world_map) = c("lon","lat")
world_map = within(world_map, {
lon = ifelse(lon < 0, lon + 360, lon)
})
ggplot(aes(x = lon, y = lat), data = world_map) + geom_path()
产生以下输出:
很明显,在主子午线的一端或另一端的多边形之间画线。我目前的解决方案是用NA替换接近本初子午线的点,将上面的
within
调用替换为:
world_map = within(world_map, {
lon = ifelse(lon < 0, lon + 360, lon)
lon = ifelse((lon < 1) | (lon > 359), NA, lon)
})
ggplot(aes(x = lon, y = lat), data = world_map) + geom_path()
这会导致正确的图像。我现在有一些问题:
orientation
中的map
参数,但将其设置为orientation = c(0,180,0)
并未产生正确的结果,实际上它并未对结果对象进行任何更改(all.equal
屈服于TRUE
)。答案 0 :(得分:28)
这可能有些棘手但你可以做到:
mp1 <- fortify(map(fill=TRUE, plot=FALSE))
mp2 <- mp1
mp2$long <- mp2$long + 360
mp2$group <- mp2$group + max(mp2$group) + 1
mp <- rbind(mp1, mp2)
ggplot(aes(x = long, y = lat, group = group), data = mp) +
geom_path() +
scale_x_continuous(limits = c(0, 360))
通过此设置,您可以轻松设置中心(即限制):
ggplot(aes(x = long, y = lat, group = group), data = mp) +
geom_path() +
scale_x_continuous(limits = c(-100, 260))
<强>已更新强>
我在这里作了一些解释:
整个数据如下:
ggplot(aes(x = long, y = lat, group = group), data = mp) + geom_path()
但是scale_x_continuous(limits = c(0, 360))
,您可以裁剪区域的一个子集,从0到360经度。
在geom_path
中,相同组的数据已连接。因此,如果mp2$group <- mp2$group + max(mp2$group) + 1
不存在,它看起来像:
答案 1 :(得分:17)
这是一种不同的方法。它的工作原理是:
maps
包转换为具有地理(纬度)CRS的SpatialLines
对象。SpatialLines
地图投影到以Prime Meridian为中心的PlateCatée(又名Equidistant Cylindrical)投影中。 (此投影与地理地图非常相似)。rgeos
包中的拓扑函数完成的。)lon_0
,取自PROJ_4
spTransform()
包中rgdal
程序使用的rgeos
程序。spTransform()
包中的拓扑函数。)这显然是很多工作,但是留下了一个最小截断的地图,并且可以使用base
轻松地重新投影。要使用lattice
或spTransform()
图形在栅格图像上叠加这些图像,我首先使用SpatialLines
重新投影栅格。如果您需要它们,同样可以投影网格线和标签以匹配library(sp)
library(maps)
library(maptools) ## map2SpatialLines(), pruneMap()
library(rgdal) ## CRS(), spTransform()
library(rgeos) ## readWKT(), gIntersects(), gBuffer(), gDifference()
## Convert a "maps" map to a "SpatialLines" map
makeSLmap <- function() {
llCRS <- CRS("+proj=longlat +ellps=WGS84")
wrld <- map("world", interior = FALSE, plot=FALSE,
xlim = c(-179, 179), ylim = c(-89, 89))
wrld_p <- pruneMap(wrld, xlim = c(-179, 179))
map2SpatialLines(wrld_p, proj4string = llCRS)
}
## Clip SpatialLines neatly along the antipodal meridian
sliceAtAntipodes <- function(SLmap, lon_0) {
## Preliminaries
long_180 <- (lon_0 %% 360) - 180
llCRS <- CRS("+proj=longlat +ellps=WGS84") ## CRS of 'maps' objects
eqcCRS <- CRS("+proj=eqc")
## Reproject the map into Equidistant Cylindrical/Plate Caree projection
SLmap <- spTransform(SLmap, eqcCRS)
## Make a narrow SpatialPolygon along the meridian opposite lon_0
L <- Lines(Line(cbind(long_180, c(-89, 89))), ID="cutter")
SL <- SpatialLines(list(L), proj4string = llCRS)
SP <- gBuffer(spTransform(SL, eqcCRS), 10, byid = TRUE)
## Use it to clip any SpatialLines segments that it crosses
ii <- which(gIntersects(SLmap, SP, byid=TRUE))
# Replace offending lines with split versions
# (but skip when there are no intersections (as, e.g., when lon_0 = 0))
if(length(ii)) {
SPii <- gDifference(SLmap[ii], SP, byid=TRUE)
SLmap <- rbind(SLmap[-ii], SPii)
}
return(SLmap)
}
## re-center, and clean up remaining streaks
recenterAndClean <- function(SLmap, lon_0) {
llCRS <- CRS("+proj=longlat +ellps=WGS84") ## map package's CRS
newCRS <- CRS(paste("+proj=eqc +lon_0=", lon_0, sep=""))
## Recenter
SLmap <- spTransform(SLmap, newCRS)
## identify remaining 'scratch-lines' by searching for lines that
## cross 2 of 3 lines of longitude, spaced 120 degrees apart
v1 <-spTransform(readWKT("LINESTRING(-62 -89, -62 89)", p4s=llCRS), newCRS)
v2 <-spTransform(readWKT("LINESTRING(58 -89, 58 89)", p4s=llCRS), newCRS)
v3 <-spTransform(readWKT("LINESTRING(178 -89, 178 89)", p4s=llCRS), newCRS)
ii <- which((gIntersects(v1, SLmap, byid=TRUE) +
gIntersects(v2, SLmap, byid=TRUE) +
gIntersects(v3, SLmap, byid=TRUE)) >= 2)
SLmap[-ii]
}
## Put it all together:
Recenter <- function(lon_0 = -100, grid=FALSE, ...) {
SLmap <- makeSLmap()
SLmap2 <- sliceAtAntipodes(SLmap, lon_0)
recenterAndClean(SLmap2, lon_0)
}
## Try it out
par(mfrow=c(2,2), mar=rep(1, 4))
plot(Recenter(-90), col="grey40"); box() ## Centered on 90w
plot(Recenter(0), col="grey40"); box() ## Centered on prime meridian
plot(Recenter(90), col="grey40"); box() ## Centered on 90e
plot(Recenter(180), col="grey40"); box() ## Centered on International Date Line
地图。
{{1}}
答案 2 :(得分:1)
这应该有效:
wm <- map.wrap(map(projection="rectangular", parameter=0, orientation=c(90,0,180), plot=FALSE))
world_map <- data.frame(wm[c("x","y")])
names(world_map) <- c("lon","lat")
map.wrap会切割穿过地图的线条。它可以通过map(wrap = TRUE)选项使用,但只有在plot = TRUE时才有效。
另一个令人烦恼的是,此时,纬度/经度是以rad为单位,而不是度数:
world_map$lon <- world_map$lon * 180/pi + 180
world_map$lat <- world_map$lat * 180/pi
ggplot(aes(x = lon, y = lat), data = world_map) + geom_path()