绘制地理空间矢量场

用 Folium 绘制地理空间矢量场

地学和许多应用领域中,数据的视觉化非常重要。尤其是一些表示方向和速度的矢量数据,例如风速、海流、车速等,使用矢量图进行绘制能够更加直观地表达这些数据的特性。

示例数据集选择

为了便于说明矢量场的绘制方法,我们选择了一个实际的例子:纽约市的 Citi Bike 数据集。Citi Bike 是纽约市一个著名的自行车共享系统,该数据集涵盖了数百万次骑行,包含每次骑行的起点和终点位置。我们将利用这些信息计算每次骑行的速度向量。

数据准备与处理

首先,我们需要导入所需的Python库并准备工作环境。以下是我们将使用的主要库:

  • 「Folium」:一个用于在Python中绘制交互式地图的库。

  • 「H3」:一个地理空间索引库,支持六边形网格划分。

  • 「Pandas」「Numpy」:用于数据处理和数值计算。

  • 「Matplotlib」:用于数据可视化。

  • 「Pyproj」:用于地理计算。

  • 「SciPy」:用于统计计算。

我们从本地的存储目录中加载Citi Bike数据集,读取每个CSV文件并将它们合并为一个DataFrame。

import jsonimport matplotlib.pyplot as plt
import numpy as npimport h3import folium
from geojson import Feature, FeatureCollectionimport math
import matplotlibfrom scipy import stats
import pandas as pdfrom pandarallel import pandarallelimport scipy.stats as scsimport os
import pandas as pd
import zipfileos.chdir('/home/mw/input/tripdata5123')zf = os.listdir('/home/mw/input/tripdata5123/202406-citibike-tripdata')
result_data = []
print("Reading:")for zfcsv in zf:print(zfcsv)df = pd.read_csv('/home/mw/input/tripdata5123/202406-citibike-tripdata/' + zfcsv, low_memory=False)result_data.append(df)df = pd.concat(result_data)
print("Done!")
result_data = None

数据清理

在进行分析之前,通常需要对数据进行清理。我们首先去掉所有缺失值(NaN)以确保后续计算的准确性。

df = df.dropna()
print(len(df))
#df = df.sample(10000)

计算骑行中点和近似航向

为了将每次骑行归纳到一个中心点,我们计算了起点和终点的中点。同时,为了简化计算,我们使用近似值来估算航向(从起点到终点的方向角度)。需要注意的是,这种近似方式并不完全精确。

# we choose the middle position instead of the start or end position to plot
df['latitude'] = (df['start_lat'] + df['end_lat'])/2.0
df['longitude'] = (df['start_lng'] + df['end_lng'])/2.0# we approximate bearing like this -- no, it is not entirely correct!
df['bearing_approx'] = 90.0 - 360 * (np.arctan2(df['end_lat'] - df['start_lat'], df['end_lng'] - df['start_lng']) / (2*math.pi))df['timestamp'] = pd.to_datetime(df['ended_at'])
df['duration'] = df['timestamp'] - pd.to_datetime(df['started_at'])
df['hour_of_day'] = df['timestamp'].dt.hour

计算距离和速度

接下来,我们使用H3库来计算每次骑行的直线距离,并利用计算出的距离和骑行时间来计算速度(km/h)。

pandarallel.initialize(progress_bar=True)distances = df.parallel_apply(lambda row: h3.point_dist((row.start_lat, row.start_lng), (row.end_lat, row.end_lng), unit='m'), axis = 1)df = df.assign(distance_in_meters=distances.values)
distances = None
speeds = df.parallel_apply(lambda row: 3.6 * row.distance_in_meters / row.duration.total_seconds(), axis = 1)df = df.assign(speed_kmh=speeds.values)
speeds = None

计算精确航向

为了得到更加精确的航向,我们使用了 pyproj 库中的 Geod 对象。这可以提供更精确的方位角计算。

import pyprojgeodesic = pyproj.Geod(ellps='WGS84')def bearing_from_lat_long_pair(start_lat, start_long, end_lat, end_long):bearing_angle, _, _ = geodesic.inv(start_long, start_lat, end_long, end_lat)if bearing_angle < 0:bearing_angle = bearing_angle + 360.0if bearing_angle > 360.0:bearing_angle = bearing_angle - 360.0return bearing_anglebearings_properly = df.parallel_apply(lambda row: bearing_from_lat_long_pair(row.start_lat, row.start_lng, row.end_lat, row.end_lng), axis = 1)df = df.assign(bearing=bearings_properly.values)bearings_properly = None

计算方向向量的x和y分量

为了更好地处理方向平均值,我们将每个方向的角度转换为x和y分量。这样,我们可以使用标准的聚合函数来计算方向的平均值。

df["direction_x"] = np.sin(2 * math.pi * df["bearing"] / 360.0)
df["direction_y"] = np.cos(2 * math.pi * df["bearing"] / 360.0)

将数据聚合到六边形网格中

现在,我们将数据聚合到六边形网格中。在本文的例子中,我们使用H3库将数据转换为分辨率为9的六边形网格单元。

df.groupby("rideable_type", as_index=False).agg({"ride_id": "count", "speed_kmh": "mean" })
# CONSTANTSH3_RESOLUTION = 9pandarallel.initialize(progress_bar=True)hex_ids = df.parallel_apply(lambda row: h3.geo_to_h3(row.latitude, row.longitude, H3_RESOLUTION), axis = 1)df = df.assign(hex_id=hex_ids.values)
hex_ids = None

现在我们有了数百万个速度矢量,我们需要将它们聚合到网格单元中, 本文的例子中是六边形。这里有个细节值得一提。取「速度」的平均值(或中位数,或其他值)很简单,你可以简单地用*“speed”: “mean”执行**groupby('hexid', …) **。取方位的平均值不能以同样的方式进行,因为方位具有360 度的圆形范围(弧度,则是 2π)。

例如,2 度(几乎向北;略微向东)和 356 度(几乎向北;略微向西)的平均值肯定不是「179」度(几乎向南!)。相反,在方向的世界中,合理的平均值是 359 度,它是一个 2 度角和一个 356 度角的圆平均值。

import numpy as np
import scipy.stats# compass bearings in degrees:
data = [2, 356]# average bearing:
print(np.mean(data)) # == 179.0, aka "wrong"
print(scipy.stats.circmean(data, high=360, low=0)) # == 359.0, aka "correct"print(np.rad2deg(np.angle(np.mean(np.cos(np.deg2rad(data)) + np.sin(np.deg2rad(data)) * 1j))%(2*math.pi)))
# == 359.0, aka also correct, but achieving the result in an overly complex way

当然,有现成的函数可以计算圆周均值 -例如scipy.stats.circmean - 但不知道如何将它与groupby一起使用,所以我采用了同样简单但不太优雅的方法,即独立平均速度矢量的 x 和 y 分量,并将arctan2函数应用于结果。

计算六边形网格单元的平均方向和速度

计算平均速度相对简单,可以直接使用 groupby 聚合函数。然而,对于方向的平均值,我们需要使用向量平均的方法。通过将方向角转换为x和y分量,然后计算这些分量的平均值,我们可以得出每个六边形单元的平均方向。

positions_df_byhex = df_subset.groupby("hex_id", as_index=False).agg({"longitude": "mean","latitude": "mean","direction_x": "mean","direction_y": "mean","bearing": "count","speed_kmh": "mean"})

另一个容易犯的错误是混淆方位(通常以北为零,顺时针测量)和数学角度(以正 x 轴为零,逆时针测量)。还有一点:如果您的矢量指的是风,风向通常是指风吹来的方向,而不是空气流动的方向。

将这些错误加在一起,很容易就会得到本来应该是逆时针的方向,但却是顺时针方向,「和/或」偏移 +90、-90 或 +180 度,「而且」从一开始就是错误聚合的。甚至没有提到弧度与度数。因此,要小心!

将自行车行程速度向量聚合到六边形单元格中,就能绘制它们了。使用六边形热图是不够的,因为对于每个单元格,除了「幅度(速度)之外,我们还有一个向量方向」(方位)。因此,我们在代码中手动设计了一个小箭头符号,并用这些箭头替换六边形,颜色可以反映速度。

arrow_tip_x = size_of_arrow_x * math.cos(bearing_rad) + center_lat
arrow_tip_y = size_of_arrow_y * math.sin(bearing_rad) + center_longarrow_back_left_x = size_of_arrow_x * math.cos(bearing_rad + 2*math.pi * 135.0 / 360.0 ) + center_lat
arrow_back_left_y = size_of_arrow_y * math.sin(bearing_rad + 2*math.pi * 135.0 / 360.0 ) + center_longarrow_back_x = size_of_arrow_x * 0.2 * math.cos(bearing_rad + 2*math.pi * 180.0 / 360.0 ) + center_lat
arrow_back_y = size_of_arrow_y * 0.2 * math.sin(bearing_rad + 2*math.pi * 180.0 / 360.0 ) + center_longarrow_back_right_x = size_of_arrow_x * math.cos(bearing_rad + 2*math.pi * 225.0 / 360.0 ) + center_lat
arrow_back_right_y = size_of_arrow_y * math.sin(bearing_rad + 2*math.pi * 225.0 / 360.0 ) + center_longcoordinates = ( (arrow_tip_x, arrow_tip_y), (arrow_back_left_x, arrow_back_left_y), (arrow_back_x, arrow_back_y), (arrow_back_right_x, arrow_back_right_y), (arrow_tip_x, arrow_tip_y) )geometry_for_row = { "type" : "Polygon", "coordinates": [ coordinates ] }

我们选择速度百分位数来利用全色彩范围,但对于某些应用程序,您可能希望使用原始值。

图片

矢量场分布

可视化矢量场

为了将这些聚合后的矢量可视化,我们需要将每个六边形网格单元中的速度和方向绘制成箭头。我们使用Folium库进行地图绘制,并在地图上绘制每个六边形单元的箭头。

绘制的结果很好,并可在地图上缩放。

图片

绘制结果

小结

通过本文的步骤,您可以学习如何从地理空间数据中提取矢量信息,并将其聚合到网格单元中进行可视化。关键点包括如何处理方向角度的聚合、如何计算速度和方向矢量,以及如何使用Folium绘制可视化地图。这种方法可以应用于许多领域,例如交通分析、气象数据分析、环境监测等。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/12523.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

深度伪造检测(Deepfake Detection):识别真假影像的关键技术

随着人工智能技术的进步&#xff0c;深度伪造&#xff08;Deepfake&#xff09;技术迅速发展。深度伪造利用深度学习技术生成高仿真的人脸、声音、影像&#xff0c;使得虚假内容可以几乎以假乱真。这一技术最早用于娱乐和广告领域&#xff0c;但逐渐被不良分子用于制造虚假信息…

基于SSD模型的高压输电线障碍物检测系统,支持图像、视频和摄像实时检测【pytorch框架、python源码】

更多目标检测和图像分类识别项目可看我主页其他文章 功能演示&#xff1a; 基于SSD模型的高压输电线障碍物检测系统&#xff0c;支持图像、视频和摄像实时检测【python源码、pytorch框架】_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于SSD模型的高压输电线障碍物…

大数据技术与应用专业教学体系如何无缝对接职业技能需求

针对高职院校大数据技术应用专业人才培养与行业需求对接中存在的岗位适应性不足等问题&#xff0c;结合教育部职业技能等级证书要求&#xff0c;本文深入分析了高职院校人才培养对接职业技能等级证书标准的必要性和可行性&#xff0c;并探索了面向岗位职业技能的专业课程体系重…

OPC学习笔记

一. 解决使用milo读取OPC设备字符串类型时&#xff0c;出现中文和特殊符号乱码的情况 解决前&#xff0c;读取字符串&#xff1a;你好 2. 解决后&#xff0c;读取字符串&#xff1a;你好 3. 解决前&#xff0c;读取字符串&#xff1a;165℃ 解决后&#xff0c;读取字符串&am…

数据结构查找-B-树(C语言代码)

#include<stdio.h> #include<stdlib.h>typedef struct Node {int level;//树的阶数int keyNum;//关键字的数量int childNum;//孩子数量int* keys;//关键字数组struct Node** children;//孩子数组struct Node* parent;//父亲指针 }Node;//初始化 Node* initNode(int…

网页web无插件播放器EasyPlayer.js播放器返回错误 Incorrect response MIME type 的解决方式

在使用EasyPlayer.js播放器进行视频流播放时&#xff0c;尤其是在SpringBoot环境中部署静态资源时&#xff0c;可能会遇到“Incorrect response MIME type”的错误&#xff0c;这通常与WebAssembly&#xff08;WASM&#xff09;文件的MIME类型配置有关。 WASM是一种新的代码格式…

[阻塞队列]

目录 1. 阻塞队列 2. 阻塞队列的优点 (1) 实现服务器之间的"低耦合". (2) 实现"削峰填谷"的功能. 3. 阻塞队列代码举例 4. 自己实现阻塞队列 1. 阻塞队列 我们知道, 标准库中原有的队列Queue及其子类, 都是线程不安全的, 所以java封装了一个名为&quo…

DCA-X 采样示波器

DCA-X 采样示波器 苏州新利通 | 综述 | DCA-X 宽带采样示波器属于我们的数字通信分析仪&#xff08;DCA&#xff09;系列。 这些示波器都是模块化平台&#xff0c;可对 50 Mb/s 到 224 Gb/s 的高速数字设计执行精准的测量。 您可以选择各种插入式模块来配置 DCA-X 主机&…

将webserver部署到公网(使用阿里云服务器)

阿里云轻量应用服务器介绍 这里我是用的是阿里云进行部署&#xff0c;阿里云推出的相关产品包括 云服务器 ECS 和轻量应用服务器。阿里云的指引和说明我觉得还是比较清楚详细的&#xff0c;适合新手。 先来介绍相关的一些名词&#xff1a; 云服务器 ECS&#xff08;Elastic …

【JavaEE进阶】Spring 事务和事务传播机制

目录 1.事务回顾 1.1 什么是事务 1.2 为什么需要事务 1.3 事务的操作 2. Spring 中事务的实现 2.1 Spring 编程式事务(了解) 2.2 Spring声明式事务 Transactional 对比事务提交和回滚的日志 3. Transactional详解 3.1 rollbackFor 3.2 Transactional 注解什么时候会…

Python 实现阿里滑块全攻略

阿里划块技术为开发者提供了高精度的视觉分割能力&#xff0c;而 Python 作为一种简洁高效的编程语言&#xff0c;可以轻松调用阿里划块接口&#xff0c;实现各种场景下的图像分割需求。 Python 调用阿里云分割抠图 - 商品分割接口的步骤如下&#xff1a;首先&#xff0c;开通…

[ComfyUI]Flux:繁荣生态魔盒已开启,6款LORA已来,更有MJ6写实动漫风景艺术迪士尼全套

今天&#xff0c;我们将向您介绍一款非常实用的工具——[ComfyUI]Flux。这是一款基于Stable Diffusion的AI绘画工具&#xff0c;旨在为您提供一键式生成图像的便捷体验。无论您是AI绘画的新手还是专业人士&#xff0c;这个工具都能为您带来极大的便利。 在这个教程中&#xff…

阿里云CDN稳定吗?

在互联网服务中&#xff0c;CDN&#xff08;内容分发网络&#xff09;扮演着至关重要的角色&#xff0c;它能够加速网站加载速度&#xff0c;提升用户体验。那么&#xff0c;作为市场上的领先者之一&#xff0c;阿里云的CDN到底稳定吗&#xff1f;九河云来和你说一说吧。 一、…

Matlab实现鹈鹕优化算法(POA)求解路径规划问题

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 鹈鹕优化算法&#xff08;POA&#xff09;是一种受自然界鹈鹕捕食行为启发的优化算法。该算法通过模拟鹈鹕群体在寻找食物时的协作行为&#xff0c;如群飞、潜水和捕鱼等&#xff0c;来探索问题的最优解。POA因其…

C++builder中的人工智能(22):在C+++中读取WAV格式的音频文件

在这篇文章中&#xff0c;我们将探讨如何在C中读取WAV格式的音频文件。音频文件是计算机科学和编程中的一个重要组成部分&#xff0c;正确使用音频可以为娱乐应用程序增添乐趣&#xff0c;或者在业务应用程序中提醒用户重要事件或状态变化。在这篇文章中&#xff0c;我们将解释…

.NET Core 应用程序如何在 Linux 中创建 Systemd 服务 ?

.NET Core 和 Linux 已经成为一个强大的组合&#xff0c;为开发人员提供了一个灵活、高性能的平台来构建和运行应用程序。在 Linux 上部署 .NET Core 应用程序的一个关键方面是利用 systemd 服务来确保应用程序顺利运行&#xff0c;在开机时自动启动&#xff0c;并在失败后重新…

@RestController 源码解读:解决 Web 开发中 REST 服务的疑难杂症

目录 一、RestContrller注解 1.1 查看底层源码 1.2 AliasFor注解说明 1.2.1 注解别名 1.2.2 元数据别名 1.3 value() 方法的作用 一、RestContrller注解 1.1 查看底层源码 首先编写如下内容&#xff1a; RestController public class TestController {} 按住 Ctrl &am…

vs2019托管调试助手 “ContextSwitchDeadlock“错误

错误描述 托管调试助手 "ContextSwitchDeadlock":“CLR 无法从 COM 上下文 0xd183e0 转换为 COM 上下文 0xd18328&#xff0c;这种状态已持续 60 秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长…

H.264/H.265播放器EasyPlayer.js RTSP播放器关于webcodecs硬解码H265的问题

EasyPlayer.js H5播放器&#xff0c;是一款能够同时支持HTTP、HTTP-FLV、HLS&#xff08;m3u8&#xff09;、WS视频直播与视频点播等多种协议&#xff0c;支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式&#xff0c;支持MSE、WASM、WebCodec等多种解码方式&#xff0c…

免费在线图片翻译工具:PicTech

文章目录 简介编辑功能 简介 PicTech是一款免费的在线图片翻译工具。图片翻译&#xff0c;顾名思义就是把图片中的文字翻译成另外一种语言&#xff0c;并以图片的形式输出。这种功能在手机的词典软件中似乎还挺常见的&#xff0c;但作为一种在线工具我还是第一次见。 其使用过…