在ggplot2中(用于地图),与定位器等效的是什么?

28
注意:这个问题是关于映射的,但我希望能在标准笛卡尔坐标系中绘图时使用它。
我喜欢基础图形,也喜欢ggplot2的许多功能。调整图形的一个最常用的基础函数是locator(n),但在ggplot2中会产生错误。
library(ggplot2) 
county_df <- map_data('county')  #mappings of counties by state
ny <- subset(county_df, region=="new york")   #subset just for NYS
ny$county <- ny$subregion

ggplot(ny, aes(long, lat, group=group)) +  geom_polygon(colour='black', fill=NA)
locator(1)

现在,正如Dason在talkstats.com上指出的那样(HERE),grid.locator()可以返回一些东西。我只是不知道如何使用这些东西来获取地图坐标。
> grid.locator()
$x
[1] 286native

$y
[1] 133native

单位似乎没有帮助,因为它们不是地图坐标。也许我需要某种转换。

提前谢谢。

编辑:(基于DWin的回答)

DWin的想法是正确的,但转换系数有点偏差。希望能帮忙解决。在下面的示例中,我有一个地图,在坐标(x = -73&y = 40.855)处有一个红点。我把DWin的回答放入一个函数中返回坐标。我期望结果是我输入的坐标,但实际上并不是。

有什么想法吗?

require(maps); library(ggplot2); require(grid)

county_df <- map_data('county')  #mappings of counties by state
ny <- subset(county_df, region=="new york")   #subset just for NYS
ny$county <- ny$subregion


NY <- ggplot(ny, aes(long, lat)) +  
          geom_polygon(aes(group=group), colour='black', fill=NA) +
          coord_map() + geom_point(aes(-73, 40.855, colour="red"))
NY  

gglocator <- function(object){
    require(maps); require(grid)
    z <- grid.locator("npc")
    y <- sapply(z, function(x) as.numeric(substring(x, 1, nchar(x))))
    locatedX <- min(object$data$long) + y[1]*diff(range(object$data$long))
    locatedy <- min(object$data$lat)  + y[2]*diff(range(object$data$lat))
    return(c(locatedX, locatedy))
}

#click on the red dot
gglocator(NY)  #I expect the results to be x = -73 & y = 40.855

编辑2:(参考Baptise的答案)

我们到达了那里。

NY <- ggplot(ny, aes(long, lat)) +  
          geom_polygon(aes(group=group), colour='black', fill=NA) +
          coord_map() + geom_point(aes(-73, 40.855, colour="red")) +
          scale_x_continuous(expand=c(0,0)) + scale_y_continuous(expand=c(0,0))


NY 
x <- grid.ls()[[1]][grep("panel-", grid.ls()[[1]])] #locate the panel
seekViewport(x)
y <-  grid.locator("npc")
y <- as.numeric(substring(y, 1, nchar(y)-3))

locatedX <- min(NY$data$long) + y[1]*diff(range(NY$data$long))
locatedy <- min(NY$data$lat) + y[2]*diff(range(NY$data$lat))
locatedX; locatedy 

更新:ggmap包gglocator函数现在包含了这个功能。


4
由于ggplot2的更改,ggmap中的ggLocator不再起作用:https://github.com/dkahle/ggmap/issues/87 - jan-glx
5个回答

10

需要使用一个有意义的单位系统,并将信息保存在ggplot对象中,这样您就可以从“npc”单位转换为地图单位:

require(maps)
require(grid)
NY <- ggplot(ny, aes(long, lat, group=group)) +  geom_polygon(colour='black', fill=NA)
 grid.locator("npc")
# clicked in middle of NY State:

#$x
#[1] 0.493649231346082npc
#
#$y
#[1] 0.556430446194226npc
 range(NY$data$long)
#[1] -79.76718 -71.87756
 range(NY$data$lat)
#[1] 40.48520 45.01157
 locatedX <- min(NY$data$long) + 0.493649231346082*diff(range(NY$data$long))
 locatedX
#[1] -75.87247
locatedY <- min(NY$data$lat) +  0.556430446194226*diff(range(NY$data$lat))
locatedY
#[1] 43.00381

谢谢您的回复。您的回答非常有道理,我已经尝试了。它得出了一个转换因子,让我们朝着正确的方向前进,但还没有到达目标。您有什么修正的想法吗?请查看我在原始帖子中的编辑。 - Tyler Rinker
1
我认为,“npc”(非玩家角色)单位只有在情节面板视口中获取才有意义。先尝试使用?seekViewport()定位到视口,然后单位应该与数据相关联。 - baptiste
我尝试从我的iPhone进行编辑,但滚动条没有呈现出来,所以今天稍后需要解决。 - IRTFM
@DWin 接管并解决了你的回答。谢谢你的帮助。 - Tyler Rinker

7

如果我在图形中添加 scale_x_continuous(expand=c(0,0)) + scale_y_continuous(expand=c(0,0)),并在执行 grid.locator() 之前执行 seekViewport("panel-3-4"),我会得到正确的结果。


1
也许你的绘图面板有不同的名称。尝试使用 grid.ls() 查找它。 - baptiste
@batise 我用grid.ls找到了它,并尝试自动化这个过程(我想把它变成一个函数),使用x <- grid.ls()[[1]][grep("panel-", grid.ls()[[1]])] #locate the panel,然后将其作为参数传递给seekViewport函数,如seekViewport(x)。这似乎可以给出正确的纬度,但不是经度(虽然我只在这一点上进行了测试)。它正在接近。 - Tyler Rinker
这可能是因为您使用了 y[2] 而不是 y[1] - baptiste
此外,convertUnit 可能比 substring 更可取:y <- c(convertUnit(y$x, "npc", valueOnly=TRUE), convertUnit(y$y, "npc", "y", valueOnly=TRUE)) - baptiste
我真是个笨蛋(我编辑了我的帖子以反映这一点)。就这样。非常感谢yo baptise和DWin。我会编写某种函数并将其作为答案返回到这里,但此答案将获得选中标记。 - Tyler Rinker
显示剩余4条评论

6
我向ggplot帮助列表写信,收到了David Kahle的非常有帮助的回复。他恰好对同样的问题感兴趣,他的函数非常优秀,因为:
1)您不必将y和x比例尺添加到图表中。
2)它可以一次找到多个点并将它们作为数据框返回。
3)它适用于任何类型的ggplot,不仅仅是地图。
gglocator <- function(n = 1, object = last_plot(), 
    message = FALSE, xexpand = c(.05,0), yexpand = c(.05, 0)){ 

  #compliments of David Kahle
  if(n > 1){
    df <- NULL
    for(k in 1:n){
      df <- rbind(df, gglocator(object = object, message = message, 
        xexpand = xexpand, yexpand = yexpand))
    }
    return(df)
  }

  x <- grid.ls(print = message)[[1]]
  x <- x[ grep("panel-", grid.ls(print=message)[[1]]) ] #locate the panel
  seekViewport(x)
  loc <-  as.numeric(grid.locator("npc"))

  xrng <- with(object, range(data[,deparse(mapping$x)]))
  yrng <- with(object, range(data[,deparse(mapping$y)]))    

  xrng <- expand_range(range = xrng, mul = xexpand[1], add = xexpand[2])
  yrng <- expand_range(range = yrng, mul = yexpand[1], add = yexpand[2])    

  point <- data.frame(xrng[1] + loc[1]*diff(xrng), yrng[1] + loc[2]*diff(yrng))
  names(point) <- with(object, c(deparse(mapping$x), deparse(mapping$y)))
  point
}

#Example 1
require(maps); library(ggplot2); require(grid)
county_df <- map_data('county')  #mappings of counties by state
ny <- subset(county_df, region=="new york")   #subset just for NYS
ny$county <- ny$subregion


NY <- ggplot(ny, aes(long, lat)) +  
          geom_polygon(aes(group=group), colour='black', fill=NA) +
          coord_map() + geom_point(aes(c(-78, -73), c(41, 40.855), 
          colour=c("blue", "red"))) + opts(legend.position = "none") 


NY 
gglocator(2)

#Example 2
df <- data.frame(xvar = 2:10, yvar = 2:10)
ggplot(df, aes(xvar, yvar)) + geom_point() + geom_point(aes(x = 3, y = 6))
gglocator()

更新: ggmap软件包gglocator函数现已包含此功能。


2
这是一个进步,但仍然不完全令人满意:1)如果轴不是线性的,则可能返回不正确的结果,2)当页面上有多个面板/图时,它可能会以某种方式失败。 - baptiste

5

这里是将DWin和Baptise提供的所有内容打包成一个函数后的最终结果。我还向ggplot帮助列表发出了询问,并将在此处报告任何额外信息。

require(maps); require(ggplot2); require(grid)

ny <- map_data('county', 'new york')

NY1 <- ggplot(ny, aes(long, lat)) +  
          geom_polygon(aes(group=group), colour='black', fill=NA) +
          coord_map() + geom_point(aes(c(-78, -73), c(41, 40.855), 
          colour=c("blue", "red"))) + opts(legend.position = "none") 

NY <- NY1 + scale_x_continuous(expand=c(0,0)) + 
          scale_y_continuous(expand=c(0,0))
          #the scale x and y have to be added to the plot

NY 

ggmap.loc <- function(object){
    x <- grid.ls()[[1]][grep("panel-", grid.ls()[[1]])] #locate the panel
    seekViewport(x)
    y <-  as.numeric(grid.locator("npc"))
    locatedX <- min(object$data$long) + y[1]*diff(range(object$data$long))
    locatedy <- min(object$data$lat) + y[2]*diff(range(object$data$lat))
    return(c(locatedX, locatedy))
}

ggmap.loc(NY)

4
这些帖子非常有用,但已经过了几年,所以有些东西已经失效。这里是一些对我有用的新代码。寻找正确的视口的代码无法正常工作,因此我使用了current.vpTree()手动搜索正确的视口,然后将其复制到seekViewport()中。请注意,对我而言,视口是'panel.6-4-6-4'而不是旧样式的panel-*。最后,当在rstudio中呈现时,我没有得到正确的答案,而是必须使用x11()。这里是一个完整的例子。希望这对你有帮助。
library(ggplot2)
library(grid)

object<-ggplot(dat=data.frame(x=1:5,y=1:5),aes(x=x,y=y)) + 
  geom_point()  +
  scale_x_continuous(expand=c(0,0)) +
  scale_y_continuous(expand=c(0,0))
x11()
print(object)
formatVPTree(current.vpTree()) #https://www.stat.auckland.ac.nz/~paul/useR2015-grid/formatVPTree.R
seekViewport('panel.6-4-6-4')
y <-  as.numeric(grid.locator("npc"))
locatedX <- min(object$data$x) + y[1]*diff(range(object$data$x))
locatedY <- min(object$data$y) + y[2]*diff(range(object$data$y))
locatedX; locatedY

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接