osm数据下载 python_用Python解锁处理OSM数据的全部姿势
OSM数据
OSM数据全称OpenStreetMap数据,是开源的全球路网数据,也是时空分析时较为常见的基础数据,本篇主要讲解如何用python优雅地处理OSM数据为下游任务做支撑。
01
OSM数据结构
空间数据的基本类型有点、线、面三种,这三种类型依据场景的不同可以用不同的存储方式存储。常见的OSM文件类型有以下三种,点、线、面对象在不同的文件类型中对应下图的不同名称。
图1 // OSM文件类型及各自内部对象名称
其中shp格式是常见的空间数据存储格式,如果经常使用ArcGIS等空间分析软件会经常与这类文件打交道,但是这类文件的体积还是偏大的。另一种xml格式则是为了方便跨平台操作而使用的文件存储格式,对于没有shp文件处理的环境而言,xml的存储方式也可以用其他的基础编译环境解析使用,但这类存储方式的存储效率还是相对偏低的。而pbf格式则是xml的protobuf版本,相比xml来说解析难度提升了,但是相对的,存储效率也大幅提高,12G的xml文件其pbf格式仅600M左右。
02
文件解析方式
不同的文件类型有不同的处理方式,笔者主要使用python进行时空数据分析,因此接下来主要介绍利用python进行这三类文件的解析方式。
图2 // OSM文件解析姿势
对于shp文件,笔者认为geopandas结合shapely进行解析处理是最为优雅的处理方式。至于shp文件的处理方式……日常挖坑,今后结合其他案例补上。
对xml文件而言,python中常见的xml解析库是lxml,但是这个库一般针对的是网页解析,适用场景不同,解析速度较慢。笔者较为推荐的方式是pyosmium,pyosmium是osmium库的python接口,提供了几乎所有OSM文件类型的解析。更为关键的是,osmium底层是用C++实现,使得文件解析处理的速度大幅度提升。
对于pbf文件,笔者进行了大量的网上调研工作,除了osmium外,并没有较为成熟的python解决方案。接下来重点介绍下pyosmium对OSM数据的处理。
Pyosmium库对OSM数据的处理流程大致可以总结为以下几个步骤:
① 定义处理数据的通用类Handler;
② 在main模块中指定读写入口;
③ 用apply指定Handler或指定的数据。
图3 // 用pysomium对OSM数据的处理流程
将上述流程转换为代码的基本框架如下。
图4 // pyosmium代码基本框架
其中Handler类继承自osmium的SimpleHandler类,这个类已经能覆盖大部分的处理任务。在Handler里面需要定义每类对象的处理方式,比如修改属性值甚至是简单的复制操作等。在main中需要先指定输入文件的路径并实例化Reader对象,接下来一般可以先实例化Handler,之后直接Handler.apply_file对应的Reader进行操作即可;如果需要将结果写入新文件,需要先实例化一个SimpleWriter对象,用osmium.apply对应的Reader、Handler和SimpleWriter。
03
举个栗子
下面以一个修改OSM数据中name字段值为osm_id值的例子作为结尾。在分析OSM数据的时候,有些场景需要明确定位所在的路段,但是很多分析软件只能返回路段的名称及经纬度,而无法返回路段的唯一标志——osm_id。另外,OSM数据中,中国的道路数据有大量的道路名称缺失,还有部分名称不标准的现象,因此将名称用osm_id替换成了一个潜在的处理需求。为了完整呈现osmium的处理功能,这里的代码步骤进行了适当扩充,单纯实现name属性值的替换并不需要这么多步骤。
首先定义Handler类。
import osmium
class Handler(osmium.SimpleHandler):
def __init__(self, idx, writer):
osmium.SimpleHandler.__init__(self)
self.idx = idx
self.writer = writer
def node(self, node):
self.writer.add_node(node)
参数中的idx后面会进行解释,这里的writer即将要写入的SimpleWriter类,由于处理结果不能覆盖原文件,因此针对不需要特殊处理的对象(node和relation)需要进行复制处理。本场景下需要处理的对象是way,首先看way模块的第一行:
def way(self, way:osmium.osm.Way):
# self.writer.add_way(way)
t_n={t.k:(t.v if not t.k.startswith('name') else str(way.id)) for t in way.tags}
t_n['name'],t_n['name:en'],t_n['name:zh']=[str(way.id)]*3
self.writer.add_way(way.replace(tags=t_n))
def relation(self, relation):
self.writer.add_relation(relation)
这里的way.tags是一个类似字典的对象,由于OSM数据中有一些固定的属性对象,比如osm_id(在这里通过way.id可以直接获取)和坐标x/y,而其他的属性值均属于在tag对象(比如name这类可以省略的属性),可以通过osm.tags获取(返回一个taglist),下图是官方对tag和taglist的解释。由于底层的C++库并不能直接返回python对象,因此返回的Tag是一个类似字典的对象,包含k/v两个属性值。
第一行将tags中所有能获取到的name属性转换为一个字典,并对属性名称起始值为“name”的属性值均替换为了way.id(由于OSM为开源数据,因此支持多种语言,可能包含英文名、中文名、日文名等)。第二行则对通用的name以及两种主流语言的name进行了替换,也可以对所有的翻译方式进行替换(这里只是举了一个指定语言进行替换的例子,第一行其实已经完成了替换的工作)。
最后使用way的replace方法将现有的tags替换成新的,然后用writer.add_way写入即可。
图5 // Tag/TagList官方说明
在main模块中指定输入输出文件路径,将输出路径作为SimpleWriter类实例化的参数。
if __name__ == '__main__':
input_file = '../../../Temp_Data/china-200116.osm.pbf'
output_file = '../data/china-output—r.osm.pbf'
writer = osmium.SimpleWriter(output_file)
idx = osmium.index.create_map('sparse_file_array,../data/node-cache-r.nodecache')
handler = Handler(idx, writer)
locations = osmium.NodeLocationsForWays(idx)
# locations.ignore_errors()
nodes=osmium.io.Reader(input_file,osmium.osm.osm_entity_bits.NODE)
osmium.apply(nodes,locations,handler)
nodes.close()
ways=osmium.io.Reader(input_file,osmium.osm.osm_entity_bits.WAY)
osmium.apply(ways,handler)
ways.close()
relations=osmium.io.Reader(input_file,osmium.osm.osm_entity_bits.RELAT
ION)
osmium.apply(relations,handler)
relations.close()
writer.close()
这里还用osmium.index.create_map新建了一个位置映射的存储对象,index对象是为了给待处理的OSM数据提供一个高效的存储容器,create_map的作用主要为了建立一个节点位置映射关系(NodeLocation)的存储文件(返回LocationTable),便于在处理的时候获取对应的节点位置信息,然后通过osmium.NodeLocationsForWays就可以获取到节点的位置信息。
接下来osmium.io.Reader是为了实例化Reader类,除了指定输入path外,还可以指定处理的对象,比如NODE/WAY/RELATION。针对nodes,输入locations可以在处理之后输出位置映射文件,方便以后处理速度的提升。利用osmium.apply方法就可以完成对各项数据的处理,之后必须要close每个处理对象,否则writer可能无法正常退出。
osm数据下载 python_用Python解锁处理OSM数据的全部姿势相关推荐
- 什么是数据标准化?在Python中如何进行数据标准化?「必学」
转载:https://www.toutiao.com/i6644145067256709645/?tt_from=weixin&utm_campaign=client_share&wx ...
- 基于BC95的数据转发,利用Python实现UDP接收数据,TCP转发数据
基于BC95的数据转发,利用Python实现UDP接收数据,TCP转发数据 文章信息 环境信息 系统概览 基于Python的UDP(服务端)数据接收 1. UDP接受的数据如何读取 文章信息 撰写日期 ...
- osm数据下载 python_批量下载osm的分区域的osm文件
# coding: utf-8 #!/usr/bin/python # #### http://www.openstreetmap.org 的分区后的osm数据批量下载工具(需要python的requ ...
- osm数据下载 python_osm数据下载 python_批量下载osm的分区域的osm文件
# coding: utf-8 #!/usr/bin/python # #### http://www.openstreetmap.org 的分区后的osm数据批量下载工具(需要python的requ ...
- 清理数据 python_在python中使用熊猫清理数据
清理数据 python In this post, we will be using the Pandas library with Python to demonstrate how to clea ...
- python爬取网页公开数据_如何用Python爬取网页数据
使用Python爬取网页数据的方法: 一.利用webbrowser.open()打开一个网站:>>> import webbrowser >>> webbrowse ...
- python怎么利用数据成像_使用Python对大脑成像数据进行可视化分析
## 简介 大脑是人类目前所知的最复杂的器官,为了很好的了解大脑这个器官,我们做了很多努力,核磁共振成像(Magnetic Resonance Image,MRI)技术就是其中的重要突破,通过MRI的 ...
- 一口气实现交通大数据爬取与Python可视化(含数据分享)
今天的文章呢主要目的不是爬虫,而是爬虫的同时顺便实现实时可视化.上次爬摩拜单车数据的文章使用的是传统的ArcGIS进行自定义可视化,硬核 | Python多线程爬取摩拜单车数据与ArcGIS可视化,今 ...
- tcga数据下载_TCGA数据挖掘(二):数据下载与整理
关于TCGA数据库中的数据下载,我们之前有介绍过R语言下载包:R语言TCGA-Assembler包下载TCGA数据,同时在介绍数据库的使用教程中也介绍了在线下载以及官方下载工具下载:TCGA数据库使用 ...
最新文章
- MOQ TIP1:简介加基础
- 科学地花钱:基于端智能的在线红包分配方案 (CIKM2020)
- linux httppost 请求接口参数被截断_记一次小程序图片安全接口和CountDownLatch的使用...
- optimize table 需要多久_吉林市政工程资质新办需要多久
- 决策树之前要不要处理缺失值_不要使用这样的决策树
- Python小练习2:pandas.Dataframe使用方法示例demo
- 进程间通信(五)—信号
- EasyUI三级联动下拉框
- sop8封装尺寸图_详解MOS管封装
- Codeforce842D Vitya and Strange Lesson
- BZOJ 2882 后缀数组的傻逼实现
- 深度学习 | MATLAB卷积神经网络原理描述
- eclipse复制行快捷键与屏幕旋转冲突的解决
- 开放正成为华为下一阶段的战略竞争力
- 亚马逊的人工智能Alexa竟然独自大笑 笑声很吓人(附视频)
- 《Java解惑》系列——02字符谜题——谜题11:最后的笑声(字符、字符串连接操作)
- 按照网络规模来分,服务器分为哪几类?
- win10新建菜单只有文件夹怎么办?
- can总线不加末端电阻_RS485总线专题讲解,从原理入手!
- C语言程序入门设计OJ练习题7 浙江大学——程序入门设计-翁恺