使用 geopandas 缓冲错误点

2024-01-15

晚上好, 我正在开发一种产品来检测订阅区域内的本地事件(罢工)。

黄色多边形应该是围绕中心红点 40KM(左)和 50KM(右)的圆圈。绿点是我的罢工,应该在我的过程中检测到。

看来我当前使用的 buffer() 没有产生预期的 40/50 Km 缓冲区半径,然后我的过程丢失了两个事件。

My code:

# Create my two events to detect
df_strike = pd.DataFrame(
    { 'Latitude': [27.0779, 31.9974],
     'Longitude': [51.5144, 38.7078]})
gdf_events = gpd.GeoDataFrame(df_strike, geometry=gpd.points_from_xy(df_strike.Longitude, df_strike.Latitude),crs = {'init':'epsg:4326'})

# Get location to create buffer
SUB_LOCATION = pd.DataFrame(
        { 'perimeter_id': [1370, 13858],
            'distance'  : [40.0, 50.0],
            'custom_lat': [31.6661, 26.6500],
            'custom_lon': [38.6635, 51.5700]})

gdf_locations  = gpd.GeoDataFrame(SUB_LOCATION, geometry=gpd.points_from_xy(SUB_LOCATION.custom_lon, SUB_LOCATION.custom_lat), crs = {'init':'epsg:4326'})

# Now reproject to a crs using meters
gdf_locations = gdf_locations.to_crs({'init':'epsg:3857'})
gdf_events = gdf_events.to_crs({'init':'epsg:3857'})

# Create buffer using distance (in meters) from locations 
gdf_locations['geometry'] = gdf_locations['geometry'].buffer(gdf_locations['distance']*1000)

# Matching events within buffer
matching_entln = pd.DataFrame(gpd.sjoin(gdf_locations, gdf_events, how='inner'))

但我的结果是一个空数据框,不应该是这样。如果我计算事件和位置之间的距离(红点和绿点之间的距离):

pnt1 = Point(27.0779, 51.5144)
pnt2 = Point(26.65, 51.57)
points_df = gpd.GeoDataFrame({'geometry': [pnt1, pnt2]}, crs='EPSG:4326')
points_df = points_df.to_crs('EPSG:3857')
points_df2 = points_df.shift() #We shift the dataframe by 1 to align pnt1 with pnt2
points_df.distance(points_df2)

返回:48662.078723米

and

pnt1 = Point(31.9974, 38.7078)
pnt2 = Point(31.6661, 38.6635)
points_df = gpd.GeoDataFrame({'geometry': [pnt1, pnt2]}, crs='EPSG:4326')
points_df = points_df.to_crs('EPSG:3857')
points_df2 = points_df.shift() #We shift the dataframe by 1 to align pnt1 with pnt2
points_df.distance(points_df2)

返回:37417.343796米

然后我期待得到这样的结果:

>>> pd.DataFrame(gpd.sjoin(gdf_locations, gdf_events, how='inner'))
   subscriber_id  perimeter_id  distance  custom_lat  custom_lon                                           geometry  index_right  Latitude  Longitude
0          19664          1370      40.0     31.6661     38.6635  POLYGON ((2230301.324 3642618.584, 2230089.452...            1   31.9974    38.7078
1          91201         13858      50.0     26.6500     51.5700  POLYGON ((3684499.890 3347425.378, 3684235.050...            0   27.0779    51.5144

我认为我的缓冲区位于 ~47KM 和 ~38KM,而不是预期的 50KM 和 40KM。我在这里遗漏了一些可以解释空结果的东西吗?


使用 geodataframe 方法进行的某些涉及距离的计算,即.distance(), .buffer()在这种特殊情况下,它们基于欧几里得几何和地图投影坐标系。他们的结果并不可靠,为了始终获得正确的结果,应该避免使用它们,而是使用地理坐标直接计算。使用适当的模块/库来执行此操作,您将获得大圆弧距离,而不是错误的欧几里德距离。从而避免神秘的(投影)错误。

在这里,我展示了可运行的代码,展示了如何按照我建议的路线进行:

import pandas as pd
import geopandas as gpd
from shapely.geometry import Polygon

import cartopy.crs as ccrs
import cartopy
import matplotlib.pyplot as plt

import numpy as np
from pyproj import Geod

# Create my two events to detect
df_strike = pd.DataFrame(
    { 'Latitude': [27.0779, 31.9974],
     'Longitude': [51.5144, 38.7078]})
gdf_events = gpd.GeoDataFrame(df_strike, geometry=gpd.points_from_xy(df_strike.Longitude, df_strike.Latitude),crs = {'init':'epsg:4326'})

# Get location to create buffer
SUB_LOCATION = pd.DataFrame(
        { 'perimeter_id': [1370, 13858],
            'distance'  : [40.0, 50.0],
            'custom_lat': [31.6661, 26.6500],
            'custom_lon': [38.6635, 51.5700]})

gdf_locations  = gpd.GeoDataFrame(SUB_LOCATION, geometry=gpd.points_from_xy(SUB_LOCATION.custom_lon, SUB_LOCATION.custom_lat), crs = {'init':'epsg:4326'})


# Begin: My code----------------
def point_buffer(lon, lat, radius_m):
    # Use this instead of `.buffer()` provided by geodataframe
    # Adapted from:
    # https://stackoverflow.com/questions/31492220/how-to-plot-a-tissot-with-cartopy-and-matplotlib
    geod = Geod(ellps='WGS84')
    num_vtxs = 64
    lons, lats, _ = geod.fwd(np.repeat(lon, num_vtxs),
                                     np.repeat(lat, num_vtxs),
                                     np.linspace(360, 0, num_vtxs),
                                     np.repeat(radius_m, num_vtxs),
                                     radians=False
                            )
    return Polygon(zip(lons, lats))

# Get location to create buffer
# Create buffer geometries from points' coordinates and distances using ...
#   special function `point_buffer()` defined above
gdf_locations['geometry'] = gdf_locations.apply(lambda row : point_buffer(row.custom_lon, row.custom_lat, 1000*row.distance), axis=1)

# Convert CRS to Mercator (epsg:3395), it will match `ccrs.Mercator()`
# Do not use Web_Mercator (epsg:3857), it is crude approx of 3395
gdf_locations = gdf_locations.to_crs({'init':'epsg:3395'})
gdf_events = gdf_events.to_crs({'init':'epsg:3395'})

# Matching events within buffer
matching_entln = pd.DataFrame(gpd.sjoin(gdf_locations, gdf_events, how='inner'))

# Visualization
# Use cartopy for best result
fig = plt.figure(figsize=(9,8))
ax = fig.add_subplot(projection=ccrs.Mercator())

gdf_locations.plot(color="green", ax=ax, alpha=0.4)
gdf_events.plot(color="red", ax=ax, alpha=0.9, zorder=23)

ax.coastlines(lw=0.3, color="gray")
ax.add_feature(cartopy.feature.LAND)
ax.add_feature(cartopy.feature.OCEAN)
ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True) 

# Other helpers
# Horiz/vert lines are plotted to mark the circles' centers
ax.hlines([31.6661,26.6500], 30, 60, transform=ccrs.PlateCarree(), lw=0.1)
ax.vlines([38.6635, 51.5700], 20, 35, transform=ccrs.PlateCarree(), lw=0.1)

ax.set_extent([35, 55, 25, 33], crs=ccrs.PlateCarree())

空间连接:

# Matching events within buffer
matching_entln = pd.DataFrame(gpd.sjoin(gdf_locations, gdf_events, how='inner'))
matching_entln[["perimeter_id", "distance", "index_right", "Latitude", "Longitude"]]  #custom_lat   custom_lon

计算检查点之间的距离

如果计算的距离小于缓冲的距离,这将检查空间连接的结果。

# Use greatcircle arc length
geod = Geod(ellps='WGS84')

# centers of buffered-circles
from_lon1, from_lon2 = [38.6635, 51.5700]
from_lat1, from_lat2 = [31.6661, 26.6500]
# event locations
to_lon1, to_lon2= [51.5144, 38.7078]
to_lat1, to_lat2 = [27.0779, 31.9974]

_,_, dist_m = geod.inv(from_lon1, from_lat1, to_lon2, to_lat2, radians=False)
print(dist_m) #smaller than 40 km == inside
# Get: 36974.419811328786 m.

_,_, dist_m = geod.inv(from_lon2, from_lat2, to_lon1, to_lat1, radians=False)
print(dist_m) #smaller than 50 km == inside
# Get: 47732.76744655724 m.

My notes

  1. 认真的地理计算应该直接通过大地测量计算来完成,而不使用任何类型的地图投影。
  2. 当您需要图形可视化时,可以使用地图投影。但需要正确计算/转换为地图投影 CRS 的正确地理值。
  3. 地图投影(网格)坐标的计算超出其允许的限制(并得到不好的结果)通常由没有经验的用户完成。
  4. 涉及使用欧几里得几何的地图/网格位置/值的计算应在各种地图变形非常低的小范围投影区域内执行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 geopandas 缓冲错误点 的相关文章

随机推荐

  • 快速标签仅留下边框

    一起早上好 i have a tableview like this 例子 在第一单元格中 我的右侧有一个红色文本标签 从它的左边我包括一个像灰线一样的图像 使用此代码我可以设置完整的绿色边框 cell Label layer border
  • 一起工作时间最长的一对员工——Python/Pandas

    我最近必须编写一个代码 返回在一个共同项目上合作最多的一对员工 这是我想出的代码 注1 Null 被程序读取为 今天 注 2 数据来自以下形式的 txt 文件 EmpID ProjectID DateFrom DateTo 1 101 20
  • 使用 Mongo-Hadoop 连接器通过 Apache Spark 更新 MongoDb 中的集合

    我想通过 Java 中的 Spark 更新 MongoDb 中的特定集合 我正在使用用于 Hadoop 的 MongoDB 连接器 https github com mongodb mongo hadoop检索并保存信息阿帕奇火花 http
  • git rebase 合并冲突

    我分叉了一个 github 存储库并在我的 github 存储库上工作 我已经提出了拉取请求并且已经完成 之后上游又有了一些提交 所以现在我想重新设置基准 我想这就是我必须做的 但我遇到了这些合并冲突 First rewinding hea
  • PostgreSQL 用户列表

    我想获取 psql 中某个数据库的用户列表 例如 template0 用户是谁 或者对于 template1 数据库 那里的用户是谁 已经尝试过 du no database is Listed not Users Select from
  • 不同环境的实体框架数据迁移

    有一些特定于开发 测试 生产环境的基础数据 我们现在在所有环境中使用实体框架迁移 但不知道如何以指定仅在开发 测试 生产上执行的迁移的方式为特定环境指定迁移 这可以在 Fluent Migrator 中使用标签属性来完成 但是实体框架呢 当
  • 如何在 Angular 2 应用程序中添加 reCAPTCHA?

    如何将 reCAPTCHA 集成到 Angular 2 应用程序中 假设您有 reCAPTCHA 给出的站点密钥和客户端密钥 将以下代码放入组件中 ViewChild captchaRef2 captchaRef2 ElementRef p
  • 操作栏中的最后一个选项卡被裁剪,消失在屏幕上

    我正在制作一个使用标签进行导航的 Android 应用程序 我在操作栏中最后一个选项卡的渲染时遇到问题 它会离开屏幕并被裁剪 据我所知 只要选项卡数量太大而无法适应屏幕宽度 就会发生这种情况 我正在使用ActionBar NAVIGATIO
  • 通过可观察限制重播缓冲区

    我有一个包含实时数据的流 以及一个基本上分隔属于一起的实时数据部分的流 现在 当有人订阅实时数据流时 我想向他们重播实时数据 但是 我不想记住所有实时数据 只想记住自上次其他流发出值以来的部分数据 有一个问题 https rx codepl
  • Play Framework 自定义资源:如何复制到目标?

    我有一个 csv 文件 必须在应用程序启动时读取该文件 我如何才能将此文件复制到目标 以 运行 或 启动 它 我正在尝试使用全局级访问此文件Global class getResourceAsStream file csv 但结果始终为空
  • 仅当使用 Web 邮件客户端时,Mailto 链接才会在新选项卡中打开

    我有一个网页 可创建联系人及其电子邮件地址列表 对于 mailto 链接 您有两个选项 1 在当前窗口中打开它或 2 在新选项卡 窗口中打开它 我看到双方都存在潜在的缺点 对于网络邮件客户端 例如 gmail 选项 1 并不理想 因为它会劫
  • 您可以在其中放置图表的 Microsoft Office 剪贴板格式有哪些?

    我正在尝试在内存中创建一个可以提供拖放操作的 DOCX 我首先尝试了 嵌入源 然而 虽然它看起来很完美 OLE 包装器中的 DOCX 但 Word 并不使用它进行拖放 尽管它 确实使用它进行剪切和粘贴 有没有办法强制Word Excel P
  • 使用 Iperf 进行 haproxy 的 udp 流量

    我正在使用 Docker 容器开展我的个人项目 关于 Haproxy 的 性能评估 我正在使用 Python 进行编程 并使用 iperf 来生成流量 我创建了几个 Docker 容器作为客户端和服务器 客户端应该通过充当负载均衡器的 Ha
  • QML 将纹理应用于网格

    我正在尝试将图像纹理应用到 QML Qt 5 6 2 中的网格 我从示例 Shadow Map QML 开始 我想对 GroundPlane 进行纹理处理 材质和效果 qml 类应用于该 GroundPlane 网格 但我看不到如何应用图像
  • 在 LINQ to SQL 中查找或创建对象的通用方法?

    很多时候在我的LINQ 到 SQL http en wikipedia org wiki Language Integrated Query LINQ to SQL 28formerly called DLINQ 29代码中 我需要 查找或
  • 获取类实例变量并使用反射打印它们的值

    我有 2 个带有 getter 和 setter 的 POJO 类 现在我试图获取该类的所有类实例变量 我知道我们可以使用反射怎么办呢 这是我的 POJO 类 它将扩展我的反射类 class Details private int age
  • 使用公司范围的超级/父 POM 覆盖超级 POM

    我们希望有一个全公司超级POM它将继承自通常的超级 POM 我们公司的所有项目都会从中继承隐式继承 这可能吗 截至目前我们必须显式继承来自我们公司范围内的超级 POM 这不是很方便 而且容易出错 有人可以建议吗 据我所知 这方面没有最佳实践
  • 使用 AJAX 时检查会话超时

    我有一个 ColdFusion 页面 用户可以打开模式并查看有关一行数据的更多信息 但是 如果用户在页面上停留的时间超过默认的 20 分钟会话超时 则会抛出错误 因为它正在查找会话变量但找不到它们 我了解如何使用服务器端代码来捕获此问题 但
  • 如何获得具有交替距离的xticks?

    我有一个条形图 其中 x 轴有国家 地区的 2 个字母标签 我必须选择一个非常小的字体 这样 x 刻度就不会相互重叠 有什么方法可以指定 x 刻度和 x 轴之间的距离 以便我可以选择更大的字体而不会重叠标签 现在 所需的示例 axis ti
  • 使用 geopandas 缓冲错误点

    晚上好 我正在开发一种产品来检测订阅区域内的本地事件 罢工 黄色多边形应该是围绕中心红点 40KM 左 和 50KM 右 的圆圈 绿点是我的罢工 应该在我的过程中检测到 看来我当前使用的 buffer 没有产生预期的 40 50 Km 缓冲