ggmap中的动态数据点标签定位

2023-11-25

我正在使用 R 中的 ggmap 包,并且对地理空间数据可视化相对较新。我有一个由十一个纬度和经度对组成的数据框,我想将其绘制在地图上,每个纬度和经度对都有一个标签。这是虚拟数据:

lat<- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,47.586349,47.512684,47.571232,47.562283)

lon<-c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)

labels<-c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D","Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")

df<-data.frame(lat,lon,labels)

现在我用annotate创建数据点标签并将其绘制在地图上;

map.data <- get_map(location = c(lon=-122.3485,lat=47.6200), 
                    maptype = 'roadmap', zoom = 11)

pointLabels<-annotate("text",x=uniqueReach$lon,y=c(uniqueReach$lat),size=5,font=3,fontface="bold",family="Helvetica",label=as.vector(uniqueReach$label))

dataPlot <- ggmap(map.data) +
 geom_point(data = uniqueReach,aes(x = df$lon, y = df$lat), alpha = 1,fill="red",pch=21,size = 6) + labs(x = 'Longitude', y = 'Latitude')+pointLabels

This produces a plot of the data points plot of data points with labels

正如您所看到的,有两个数据点在 (-122.44,47.63) 周围重叠,并且它们的标签也重叠。现在,我可以手动向每个标签点添加偏移,以防止标签重叠(请参阅这个帖子),但是当我需要为不同的纬度和经度对集生成许多这样的图时,这不是一个很好的技术。

有没有办法自动防止数据标签重叠?我意识到标签是否重叠取决于实际的图形尺寸,因此如果需要,我愿意将图形尺寸固定在某些尺寸。预先感谢您的任何见解!

EDIT

以下是使用 Sandy Mupratt 给出的答案修改后的代码

# Defining function to draw text boxes
draw.rects.modified <- function(d,...){
  if(is.null(d$box.color))d$box.color <- NA
  if(is.null(d$fill))d$fill <- "grey95"
  for(i in 1:nrow(d)){
    with(d[i,],{
      grid.rect(gp = gpar(col = box.color, fill = fill,alpha=0.7),
                vp = viewport(x, y, w, h, "cm", c(hjust, vjust=0.25), angle=rot))
    })
  }
  d
}


# Defining function to determine text box borders
enlarge.box.modified <- function(d,...){
  if(!"h"%in%names(d))stop("need to have already calculated height and width.")
  calc.borders(within(d,{
    w <- 0.9*w
    h <- 1.1*h
  }))
}

生成绘图:

dataplot<-ggmap(map.data) + 
                 geom_point(data = df,aes(x = df$lon, y = df$lat), 
                            alpha = 1, fill = "red", pch = 21, size = 6) + 
                  labs(x = 'Longitude', y = 'Latitude') +
                  geom_dl(data = df, 
                      aes(label = labels), 
                      list(dl.trans(y = y + 0.3), "boxes", cex = .8, fontface = "bold"))

ggmap plot with labels within text boxes

这是一个更具可读性的情节,但有一个悬而未决的问题。您会注意到标签“Site 1E”开始与与“Site 1A”关联的数据点重叠。 directlabels 是否有办法处理与属于另一个标签的数据点重叠的标签?

我对此的最后一个问题是如何使用此方法绘制多个重复标签。假设 data.frame 的标签全部相同:

df$labels<-rep("test",dim(df)[1])

When I use the same code, directlabels removes the duplicate label names: enter image description here

但我希望每个数据点都有一个“测试”标签。有什么建议么?


编辑 2016 年 1 月 11 日:使用ggrepel package with ggplot2v2.0.0 和ggmap v2.6

ggrepel效果很好。在下面的代码中,geom_label_repel()显示一些可用的参数。

lat <- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,
         47.586349,47.512684,47.571232,47.562283)
lon <- c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,
        -122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels <- c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D",
        "Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")

df <- data.frame(lat,lon,labels)

library(ggmap)
library(ggrepel)
library(grid)

map.data <- get_map(location = c(lon = -122.3485, lat = 47.6200), 
                    maptype = 'roadmap', zoom = 11)

ggmap(map.data) + 
   geom_point(data = df, aes(x = lon, y = lat), 
      alpha = 1, fill = "red", pch = 21, size = 5) + 
   labs(x = 'Longitude', y = 'Latitude') +
   geom_label_repel(data = df, aes(x = lon, y = lat, label = labels), 
                 fill = "white", box.padding = unit(.4, "lines"),
                 label.padding = unit(.15, "lines"),
                 segment.color = "red", segment.size = 1)

enter image description here



原始答案但已更新ggplotv2.0.0 和ggmap v2.6

如果只有少量重叠点,则使用直接标签包中的“top.bumpup”或“top.bumptwice”方法可以将它们分开。在下面的代码中,我使用geom_dl()函数来创建和定位标签。

 lat <- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,
         47.586349,47.512684,47.571232,47.562283)
 lon <- c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,
        -122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
 labels <- c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D",
        "Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
 df <- data.frame(lat,lon,labels)

library(ggmap)
library(directlabels)

map.data <- get_map(location = c(lon = -122.3485, lat = 47.6200), 
                    maptype = 'roadmap', zoom = 11)
ggmap(map.data) + 
   geom_point(data = df, aes(x = lon, y = lat), 
      alpha = 1, fill = "red", pch = 21, size = 6) + 
   labs(x = 'Longitude', y = 'Latitude') +
   geom_dl(data = df, aes(label = labels), method = list(dl.trans(y = y + 0.2), 
      "top.bumptwice", cex = .8, fontface = "bold", family = "Helvetica"))

enter image description here

编辑:调整底层标签

我想到了几种方法,但都不是完全令人满意。但我认为您不会找到适用于所有情况的解决方案。

为每个标签添加背景颜色
这是一个解决方法,但是directlabels具有“盒子”功能(即标签放置在盒子内)。看起来应该能够修改列表中的背景填充和边框颜色geom_dl,但我无法让它工作。相反,我采用两个函数(draw.rects and enlarge.box) 来自直接标签网站;修改它们;并将修改后的函数与“top.bumptwice”方法结合起来。

draw.rects.modified <- function(d,...){
  if(is.null(d$box.color))d$box.color <- NA
  if(is.null(d$fill))d$fill <- "grey95"
  for(i in 1:nrow(d)){
    with(d[i,],{
      grid.rect(gp = gpar(col = box.color, fill = fill),
                vp = viewport(x, y, w, h, "cm", c(hjust, vjust=0.25), angle=rot))
    })
  }
  d
}

enlarge.box.modified <- function(d,...){
  if(!"h"%in%names(d))stop("need to have already calculated height and width.")
  calc.borders(within(d,{
    w <- 0.9*w
    h <- 1.1*h
  }))
}

boxes <-
  list("top.bumptwice", "calc.boxes",  "enlarge.box.modified", "draw.rects.modified")

ggmap(map.data) + 
   geom_point(data = df,aes(x = lon, y = lat), 
      alpha = 1, fill = "red", pch = 21, size = 6) + 
   labs(x = 'Longitude', y = 'Latitude') +
   geom_dl(data = df, aes(label = labels), method = list(dl.trans(y = y + 0.3), 
      "boxes", cex = .8, fontface = "bold"))

enter image description here

为每个标签添加轮廓
另一种选择是使用这个方法为每个标签提供一个轮廓,尽管目前还不清楚它如何与直接标签一起使用。因此,需要手动调整坐标,或者在数据帧中搜索给定阈值内的坐标,然后进行调整。然而,在这里,我使用pointLabel函数来自maptools包装来定位标签。不能保证它每次都能工作,但我用你的数据得到了合理的结果。它内置了一个随机元素,因此您可以运行几次,直到获得合理的结果。另请注意,它将标签放置在基本图中。然后必须提取标签位置并将其加载到 ggplot/ggmap 中。

lat<- c(47.597157,47.656322,47.685928,47.752365,47.689297,47.628128,47.627071,47.586349,47.512684,47.571232,47.562283)
lon<-c(-122.312187,-122.318039,-122.31472,-122.345345,-122.377045,-122.370117,-122.368462,-122.331734,-122.294395,-122.33606,-122.379745)
labels<-c("Site 1A","Site 1B","Site 1C","Site 2A","Site 3A","Site 1D","Site 2C","Site 1E","Site 2B","Site 1G","Site 2G")
df<-data.frame(lat,lon,labels)

library(ggmap)
library(maptools)  # pointLabel function

# Get map
map.data <- get_map(location = c(lon=-122.3485,lat=47.6200), 
                    maptype = 'roadmap', zoom = 11)

bb = t(attr(map.data, "bb"))   # the map's bounding box

# Base plot to plot points and using pointLabels() to position labels
plot(df$lon, df$lat, pch = 20, cex = 5, col = "red", xlim = bb[c(2,4)], ylim = bb[c(1,3)])
new = pointLabel(df$lon, df$lat, df$labels, pos = 4, offset = 0.5, cex = 1)
new = as.data.frame(new)
new$labels = df$labels

## Draw the map
map = ggmap(map.data) + 
       geom_point(data = df, aes(x = lon, y = lat), 
          alpha = 1, fill = "red", pch = 21, size = 5) + 
       labs(x = 'Longitude', y = 'Latitude') 

## Draw the label outlines 
theta <- seq(pi/16, 2*pi, length.out=32)
xo <- diff(bb[c(2,4)])/400
yo <- diff(bb[c(1,3)])/400

for(i in theta) {
    map <- map + geom_text(data = new,  
       aes_(x = new$x + .01 + cos(i) * xo, y = new$y + sin(i) * yo, label = labels), 
                  size = 3, colour = 'black', vjust = .5, hjust = .8)
}

# Draw the labels
map + 
   geom_text(data = new, aes(x = x + .01, y = y, label=labels), 
     size = 3, colour = 'white', vjust = .5, hjust = .8)

enter image description here

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ggmap中的动态数据点标签定位 的相关文章

随机推荐

  • 通过 VBScript 了解用户是否具有管理权限的最佳方法

    我需要检查执行脚本的用户是否具有计算机的管理权限 我已经指定了执行脚本的用户 因为该脚本可以使用除使用类似于 Runas 的用户登录之外的用户执行 Javier 这两种解决方案都可以在安装了英文版 Windows 的 PC 上运行 但如果安
  • 获取 contenteditable div 中的插入符索引(包括标签)

    我有一个contentEditable div其中我有多个标签 br b u i 和文本 我需要获取相对于 div 的插入符索引位置 包括所有标签 例如 div abc b def br ghi b jkl div 如果光标位于g and
  • 调用派生类的构造函数在基类的构造函数之前执行

    好吧 最初我在每个派生类中都有几个具有不同值的常量 例如 MAX SPEED 这个想法是在基类的某些方法中使用这些值 就在那时 我意识到我无法使用常量来做到这一点 因此我创建了只读属性 我需要一种方法在实例化时将这些值分配给私有字段 最好是
  • 为什么法线使用相机空间而不是模型空间?

    我正在学习 OpenGL 图形 并且正在学习阴影 我正在阅读的教程告诉我将法线和光矢量转换为相机空间 为什么是这样 为什么不能将坐标保留在模型空间中 随之而来的问题是如何处理模型转换 我无法找到明确的答案 我目前有这个代码 vec3 nor
  • 您可以在 irb 会话中自动在每个命令中“要求”ruby 文件吗?

    我当前正在编辑一个文件 并使用 irb 来测试 api gt require file rb gt o Object new gt o method 然后我希望能够编辑 file rb 并能够立即看到更改 示例 假设当我第一次需要 file
  • 包管理器名称未找到异常

    我是安卓编程新手 我使用 Eclipse 以及 MainActivity java 和 ClassFragment java 文件创建了一个应用程序 ClassFragment 是一个片段 我正在使用新更新的 appcompat 库 我只想
  • GLSL:关于相干限定符

    我没明白如何coherent限定符和原子操作一起工作 我使用以下代码在同一 SSBO 位置上执行一些累积操作 uint prevValue newValue uint readValue ssbo index do prevValue re
  • Blazor:没有会话/JWT 令牌时重定向到登录页面?

    我正在尝试在 Blazor 中创建一个新应用程序并正在进行身份验证 我正在使用存储在本地存储中的 JWT 令牌 当应用程序加载时 我需要检查存储中是否有令牌 如果是这样 请将其添加到所有 API 请求的 HTTP 标头中 如果不是 则在页面
  • 在 Swift 中旋转 UIImage

    我正在使用 Xcode 6 0 1 和 Swift 我有一个 UIImage 我想使用旧图像作为源来制作另一个图像 新图像以某种方式旋转 比如说垂直翻转 这个问题已经有答案了几个月前 然而 即使情况相同 该解决方案对我不起作用 当我有 va
  • Application.OnKey 无法正确重置

    I am trying to help another user in this forum reference The goal is to use the Enter key on the numeric keypad to trigg
  • Python、Matplotlib、绘制多线(数组)和动画

    我开始使用 Python 和 OOP 编程 但我在 Fortran 90 95 和 Matlab 编程方面拥有丰富的经验 我正在 tkinter 环境上使用动画开发一个小工具 该工具的目标是对多行进行动画处理 数组而不是数据向量 下面是我的
  • 如何读取 emscripten 编译库中用户指定的文件?

    我目前正在开发一个带有 emscripten 编译支持的 C 文件解析库 它从用户处获取文件路径 在其中读取二进制文件并解析它 据我所知 emscripten 不支持直接加载文件 而是使用虚拟文件系统 有没有办法将给定路径上的文件加载到虚拟
  • 如何使用 swift 隐藏 QLPreviewController 中的共享按钮?

    我使用下面的代码来使用 QLPreviewcontroller 在我的应用程序中显示一些文档 let ql QLPreviewController ql dataSource self ql navigationItem rightBarB
  • 如何使用配置文件提供程序插件从 Jenkins 管道内的配置文件读取属性

    我想用一个简单的属性配置文件参数化我的 Jenkins 管道 skip tests true 我已将其添加到 Jenkins 配置文件管理中 在我的管道中 我导入此文件并尝试使用 Jenkins 管道配置文件插件读取它 node my sw
  • 混合模式程序集未加载本机 C++ pdb 的符号

    我正在使用 C CLI 中的混合模式程序集 在混合模式组装中成功时 所有托管模式组装的 pdb 都会被加载 但即使本机 pdb 的信息显示在 模块 窗格中 即在 VS 调试 gt Windows gt 模块中 也不会加载本机 dll 和 p
  • 计算Javascript中两个日期之间的工作日(节假日除外)

    我有一个 javascript 函数 它计算两个日期之间的工作日 它可以工作 但问题是它不考虑假期 如何修改此函数 例如通过在异常数组中添加假期 在互联网上搜索了这个问题 但没有找到有关假期例外的信息 例如假期数组 var holidays
  • 附加模板字符串

    是否可以将模板字符串附加到 div 中 我正在尝试优化我的代码 目前我的代码必须创建元素 添加类 添加文本节点 然后将所有内容附加在一起 我想知道是否可以只创建一个模板字符串然后附加它 以提高效率 我不想用innerHTML 擦除当前div
  • 默认参数为泛型类型

    我有用 Swift 编写的协议及其实现 protocol P struct A P 协议用作某些功能的泛型类型 func foo
  • 如何确定是否由于共享冲突而引发 IOException?

    我有一个 C 应用程序 我想将文件复制到新位置 有时我需要覆盖现有文件 当发生这种情况时 我收到 System IO IOException 我想从共享冲突中恢复 但如何确定返回 IOException 是因为目标文件正在使用而不是其他原因
  • ggmap中的动态数据点标签定位

    我正在使用 R 中的 ggmap 包 并且对地理空间数据可视化相对较新 我有一个由十一个纬度和经度对组成的数据框 我想将其绘制在地图上 每个纬度和经度对都有一个标签 这是虚拟数据 lat lt c 47 597157 47 656322 4