用folium在物体上绘制航向

Posted

技术标签:

【中文标题】用folium在物体上绘制航向【英文标题】:plot heading direction with folium onto an object 【发布时间】:2021-11-19 17:29:16 【问题描述】:

我用以下数据绘制了一张热图。

我有数千行。它只是一个样本。我还想查看该坐标的谷歌地图视图。所以我做了这样的事情。

import folium
from folium.plugins import HeatMap
from folium.plugins import FastMarkerCluster


default_location=[11.1657, 45.4515]
m = folium.Map(location=default_location, zoom_start=13)


heat_data = [[row['lat'],row['lon']] for index, row in test.iterrows()]

# Plot it on the map
HeatMap(heat_data).add_to(m)

callback = ('function (row) ' 
                'var marker = L.marker(new L.LatLng(row[0], row[1]), color: "red");'
                'var icon = L.AwesomeMarkers.icon('
                "icon: 'info-sign',"
                "iconColor: 'white',"
                "markerColor: 'green',"
                "prefix: 'glyphicon',"
                "extraClasses: 'fa-rotate-0'"
                    ');'
                'marker.setIcon(icon);'
                "var popup = L.popup(maxWidth: '300');"
                "const display_text = text1: row[0], text2: row[1];"
                "var mytext = $(`<div id='mytext' class='display_text' style='width: 100.0%; height: 100.0%;'>\
                <a href=https://https://www.google.com/maps?ll=$display_text.text1,$display_text.text2 target='_blank'>Open Google Maps</a></div>`)[0];"
                "popup.setContent(mytext);"
                "marker.bindPopup(popup);"
                'return marker;')
            
m.add_child(FastMarkerCluster(heat_data, callback=callback))


# Display the map
m

现在对于每个 gps 坐标,我想在角度上绘制 一个小箭头几个小箭头 heading_direction 并在可能的情况下从 gps 坐标的角度显示 distance_of_item。预期的结果可能是这样的。

在上图中,位置指针是gps坐标,方向和角度将根据航向方向角度,并绘制了一个小星星,即物体。对象应放置在数据集中提到的距离(以米为单位)处。我不确定如何实现这一目标。任何线索或建议都是最受欢迎的。谢谢!

【问题讨论】:

嗨,Deb,您介意详细说明预期的输出吗? 嗨@rpanai,我已经编辑了问题并添加了预期的输出 【参考方案1】: 鉴于您的样本数据是图像,已使用备用 GPS 数据(英国医院),然后将距离和方向列添加为随机值 给定要求是在由距离和方向定义的位置绘制标记,第一步是计算其 GPS 坐标。
    使用 UTM CRS 使距离有意义 在 UTM CRS 中使用高中数学计算 xy 将 CRS 转换回 WSG 84 以便拥有 GPS 坐标
您已将问题标记为 plotly,因此我使用 ma​​pbox 线和散点跟踪来演示构建平铺地图 样本数据为1200+家医院,表现不错 geopandas 数据框也可用于构建 folium 瓷砖/标记。关键步骤是计算 GPS 坐标
import geopandas as gpd
import pandas as pd
import numpy as np
import shapely
import math
import plotly.express as px
import plotly.graph_objects as go
import io, requests
# get some public addressess - hospitals.  data that has GPS lat / lon
dfhos = pd.read_csv(io.StringIO(requests.get("http://media.nhschoices.nhs.uk/data/foi/Hospital.csv").text),
    sep="¬",engine="python",).loc[:, ["OrganisationName", "Latitude", "Longitude"]]

# debug with fewer records
# df = dfhos.loc[0:500]
df = dfhos

# to use CRS transformations use geopandas, initial data is WSG 84, transform to UTM geometry
# directions and distances are random
gdf = gpd.GeoDataFrame(
    data=df.assign(
        heading_direction=lambda d: np.random.randint(0, 360, len(d)),
        distance_of_item=lambda d: np.random.randint(10 ** 3, 10 ** 4, len(d)),
    ),
    geometry=df.loc[:, ["Longitude", "Latitude"]].apply(
        lambda r: shapely.geometry.Point(r["Longitude"], r["Latitude"]), axis=1
    ),
    crs="EPSG:4326",
).pipe(lambda d: d.to_crs(d.estimate_utm_crs()))

# standard high school geometry...
def new_point(point, d, alpha):
    alpha = math.radians(alpha)
    return shapely.geometry.Point(
        point.x + (d * math.cos(alpha)),
        point.y + (d * math.sin(alpha)),
    )

# calculate points based on direction and distance in UTM CRS.  Then convert back to WSG 84 CRS
gdf["geometry2"] = gpd.GeoSeries(
    gdf.apply(
        lambda r: new_point(
            r["geometry"], r["distance_of_item"], r["heading_direction"]
        ),
        axis=1,
    ),
    crs=gdf.geometry.crs,
).to_crs("EPSG:4326")
gdf = gdf.to_crs("EPSG:4326")


# plot lines to show start point and direct.  plot markers of destinations for text of distance, etc
fig = px.line_mapbox(
    lon=np.stack(
        [gdf.geometry.x.values, gdf.geometry2.x.values, np.full(len(gdf), np.nan)],
        axis=1,
    ).reshape([1, len(gdf) * 3])[0],
    lat=np.stack(
        [gdf.geometry.y.values, gdf.geometry2.y.values, np.full(len(gdf), np.nan)],
        axis=1,
    ).reshape([1, len(gdf) * 3])[0],
).add_traces(
    px.scatter_mapbox(
        gdf,
        lat=gdf.geometry2.y,
        lon=gdf.geometry2.x,
        hover_data=["distance_of_item", "OrganisationName"],
    ).data
)
# c = gdf.loc[]
fig.update_layout(mapbox="style": "open-street-map", "zoom": 8, 'center': 'lat': 52.2316838387109, 'lon': -1.4577750831062155, margin="l":0,"r":0,"t":0,"r":0)

【讨论】:

哇,看起来不错。我正在考虑使用haversine距离公式来获取点的坐标。另外,您能否建议为什么我得到 gdf.estimate_utm_crs() 的属性错误 -> 'GeoDataFrame' 对象没有属性 'estimate_utm_crs'。我尝试使用最新的 geopandas 版本 0.10.0。仍然收到错误。 我使用的是 geopandas 0.9.0,刚刚升级到 0.10.0 仍然可以使用...最小代码 gpd.GeoDataFrame(data=pd.DataFrame("name":["test"]), geometry=[shapely.geometry.Point(0.406042, 51.379997)], crs="EPSG:4326").estimate_utm_crs() 可以使用吗? 不,仍然收到 AttributeError:'GeoDataFrame' 对象没有属性 'estimate_utm_crs'。我不确定这里有什么问题 import pyproj import geopandas as gpd print(gpd.__version__, pyproj.__version__) 这会返回什么?对我来说 0.10.0 3.2.1。我怀疑你在一个 venv 中运行 geopandas 不是你认为的版本...... 啊,你是对的,在我运行的环境中有 0.6.1 版本的 geopandas。非常感谢!!

以上是关于用folium在物体上绘制航向的主要内容,如果未能解决你的问题,请参考以下文章

无法用folium绘制地图

folium:绘制地图的模块

用 folium 绘制标记是不是有限制?

使用 Python 地图绘制工具 -- folium 全攻略

使用 Python 地图绘制工具 -- folium 全攻略

使用 Python 地图绘制工具 -- folium 全攻略