在大型 GIS 数据库中按属性高效溶解相邻多边形

article/2025/7/5 10:50:43

您是否拥有一个大型 GIS 数据集,并希望高效地融合所有具有相同属性的相邻多边形?在本文中,我将分享如何使用 PostGIS 处理包含超过 75 万行数据的土地利用数据集来实现这一目标。

我将以维多利亚州土地利用数据集为例。该数据可从Data VIC免费获取。

动机

geopandas首先,让我们使用Python绘制一小组数据样本,这样我就可以解释我想要溶解多边形的动机。

由于数据保存在 PostGIS 表中,我们首先要创建与数据库的连接。

import psycopg
from sqlalchemy import create_engine# database configuration
user = '<username>'
host = 'localhost'
database = '<dbname>'
driver = 'postgresql+psycopg'
connection_str = f'{driver}://{user}@{host}/{database}'engine = create_engine(connection_str)

我只想对数据子集进行采样,因此我只会过滤随机位置 (-36.8, 144.1) 0.025 度范围内的多边形。

import geopandas as gpdsql = """
SELECT alumv8, geometry
FROM vic_landuse
WHERE ST_DWithin(geometry,ST_GeomFromText('POINT(144.1 -36.8)', 7844), 0.025)AND ST_geometrytype(geometry) = 'ST_Polygon'
"""sample = gpd.read_postgis(sql, engine, geom_col="geometry")
sample['alumv8'] = sample['alumv8'].astype('category')ax = sample.plot('alumv8',legend=True,legend_kwds=dict(loc='upper left',bbox_to_anchor=(1.05, 1),title='ALUM codes')
)
ax.tick_params('x', rotation=45)

没有任何

在上面的地图中,我们有许多相邻的地块具有相同的属性(在本例中为alumv8)。我想根据土地用途创建自定义图块;因此我对单个地块不感兴趣。出于处理目的,我可以通过合并具有相同属性的相邻多边形来减少几何图形的数量。

使用数据子集进行演示

首先,我将逐步演示如何使用上面创建的小子集数据框来实现这一点。然后,我们可以创建一个脚本来自动化整个表的流程。

%load_ext sql
%sql postgresql+psycopg://<username>@localhost/<dbname

我将使用示例数据创建一个新表。

%%sql
CREATE TABLEsample_landuse AS
SELECT*
FROMvic_landuse
WHEREST_DWithin (geometry,ST_GeomFromText ('POINT(144.1 -36.8)', 7844),0.025)AND ST_geometrytype (geometry) = 'ST_Polygon'
%%sql
SELECTalumv8,COUNT(alumv8)
FROMsample_landuse
GROUP BYalumv8;

没有任何

每个 ALUM 代码中的多边形数量。

简要流程

我遵循的流程是:

  1. 为每个 ALUM 代码创建一个视图。
  2. 在每个代码中,如果几何图形相邻,则将其溶解,从而生成一个单独的表。
  3. 连接在步骤 2 中创建的所有表。
  4. 清理所有中间视图和表。

我将通过下面的示例演示这些步骤。

为每个 ALUM 代码创建一个视图

这很简单。在本例中,我们使用 ALUM 代码320

%%sql
CREATE VIEWlanduse_320 AS
SELECT*
FROMsample_landuse
WHEREalumv8 = 320;
溶解每个代码中的相邻几何图形

ST_ClusterDBSCAN是一个窗口函数它返回每个输入几何体的聚类编号。相邻的几何体会被赋予相同的聚类编号。

我们将使用ST_ClusterDBSCAN(geometry, 0, 2),因为我们希望将彼此相距 0 个单位(度)以内的几何图形进行聚类,并且我们希望聚类中至少有两个几何图形。

%%sql
CREATE TABLElanduse_320_clustered AS
SELECTalumv8,ST_ClusterDBSCAN (geometry, 0, 2) OVER () AS cluster_id,geometry
FROMlanduse_320;

我们可以看到已经创建了多个至少包含 2 个多边形的集群。

%%sql
SELECTcluster_id,COUNT(cluster_id)
FROMlanduse_320_clustered
GROUP BYcluster_id
ORDER BYCOUNT desc
LIMIT5;

没有任何

每个簇内的多边形数量。

接下来,如果行具有相同的cluster_id ,我们将使用 PostGIS 的 ST_Union 方法分解这些行。

%%sql
CREATE TABLElanduse_320_dissolved AS
SELECTalumv8,ST_Union (geometry) AS geometry
FROMlanduse_320_clustered
GROUP BYalumv8,cluster_id;

现在,我们只有 10 个多边形,而不是最初开始的 30 个。

%sql SELECT COUNT(*) FROM landuse_320_dissolved;

没有任何

重复所有 ALUM 代码

现在,我们可以循环遍历表中的所有 ALUM 代码,并对每个代码重复上述过程。

BEGIN
-- the new table
CREATE TABLE landuse_dissolved (alumv8 int, geometry geometry);FOR alum_code INSELECT DISTINCT alumv8 FROM sample_landuse
LOOPEXECUTE format('DROP VIEW IF EXISTS landuse_%s', alum_code);-- create view for the codeEXECUTE format('CREATE VIEW landuse_%s ASSELECT * FROM sample_landuseWHERE alumv8 = %L',alum_code, alum_code);-- create clustered tableEXECUTE format('CREATE TABLE landuse_%s_clustered ASSELECTalumv8,ST_ClusterDBSCAN(geometry, 0, 2) OVER() AS cluster_id,geometryFROM landuse_%s', alum_code, alum_code);-- dissolve adjacent geometriesEXECUTE format('CREATE TABLE landuse_%s_dissolved ASSELECT alumv8, ST_Union(geometry) as geometryFROM landuse_%s_clusteredGROUP BY alumv8, cluster_id',alum_code, alum_code);-- add dissolved geometries to new tableEXECUTE format('INSERT INTO landuse_dissolved (alumv8, geometry)SELECT alumv8, geometryFROM landuse_%s_dissolved', alum_code);-- cleanup intermediary views and tablesEXECUTE format('DROP TABLE landuse_%s_clustered', alum_code);EXECUTE format('DROP VIEW landuse_%s', alum_code);EXECUTE format('DROP TABLE landuse_%s_dissolved', alum_code);COMMIT;
END LOOP;
END $$
original_rows = %sql SELECT COUNT(*) FROM sample_landuse;
new_rows = %sql SELECT COUNT(*) FROM landuse_dissolved;print(f"original rows = {original_rows[0].count}")
print(f"rows after dissolving = {new_rows[0].count}")

原始行数 = 94 溶解后行数 = 29

因此,在溶解相邻多边形之后,多边形数量从原来的 94 个减少到 29 个。现在让我们将溶解后的表格绘制landuse_dissolved在原始表格旁边sample,并直观地检查上述过程的影响。

import matplotlib.pyplot as pltsql = "SELECT * FROM landuse_dissolved"
sample_dis = gpd.read_postgis(sql, engine, geom_col="geometry")
sample_dis['alumv8'] = sample_dis['alumv8'].astype('category')fig, (ax1, ax2) = plt.subplots(1, 2, sharey=True)sample.plot('alumv8', ax=ax1)
sample_dis.plot('alumv8', ax=ax2)for ax in [ax1, ax2]:ax.set_xticks([])ax.set_yticks([])

没有任何

左图:原始数据集。右图:使用 ALUM 代码溶解相邻多边形后的结果。

我们可以看到,除了具有相同 ALUM 代码的相邻几何体中单个地块的边界外,没有任何信息丢失。因此,我们可以确认获得了所需的结果,现在可以对整个数据集进行相同的操作。

面积小了?

这里需要注意的是,总面积会小于原始面积。这主要是由于融合过程中几何形状被简化,或者消除了多边形之间的重叠区域。

让我们计算每个 ALUM 代码的总面积,并比较两个表的结果。 注意:由于几何体的 CRS 是地理坐标系(EPSG:7844,单位为度),因此我们需要将几何体转换为相应的平面 CRS(EPSG:3111,单位为米)来计算面积。

我们可以创建一个数据框,记录面积差异(以平方米为单位)。结果显示,123个ALUM代码中,有77个的总面积存在差异。

%%sql
original_area <<
SELECTalumv8,SUM(ST_Area (ST_Transform (geometry, 3111))) AS area
FROMsample_landuse
GROUP BYalumv8;
%%sql
new_area <<
SELECTalumv8,SUM(ST_Area (ST_Transform (geometry, 3111))) AS area
FROMlanduse_dissolved
GROUP BYalumv8;

我们可以创建一个数据框,记录面积差异(以平方米为单位)。结果显示,123个ALUM代码中,有77个的总面积存在差异。

area= original_area.DataFrame().set_index('alumv8').join(new_area.DataFrame().set_index('alumv8'), how='inner', rsuffix='_new')
area['diff'] = area['area'] - area['area_new']
area['diff_pct'] = 100 * (area['area'] - area['area_new']) / area['area']area

没有任何

原始数据集和溶解数据集之间每个 ALUM 代码的总面积(和差异)。

我们可以看到,5/8 ALUM 代码的面积有所不同。虽然对于此示例数据集而言,差异很小,但当数据集较大时,差异可能会累积起来。

因此,在决定这种溶解是否适合当前任务时,牢记这一点很重要。

溶解整个数据集中的相邻多边形

当然,对于超过 75 万行的整个数据集,使用相同的 ALUM8 代码溶解所有相邻多边形是一个昂贵且耗时的过程。或许可以休息一会儿喝杯咖啡,或者舒展一下筋骨?

但结果相当令人印象深刻。最终只有约 112k 行,减少了 85%。

original_rows = %sql SELECT COUNT(*) FROM vic_landuse;
new_rows = %sql SELECT COUNT(*) FROM vic_landuse_dissolved;print(f"original rows = {original_rows[0].count}")
print(f"rows after dissolving = {new_rows[0].count

原始行数 = 751295 溶解后行数 = 112603

在某些任务中,例如使用减少的行数进行绘图,我们可以立即看到差异。在我的电脑上,使用geopandas绘制原始数据集大约需要 2 分钟,而处理合并后的数据集只需要大约 50 秒。

sql = "SELECT * FROM vic_landuse"
vic_landuse = gpd.read_postgis(sql, engine, geom_col="geometry")
vic_landuse["alumv8"] = vic_landuse["alumv8"].astype("category")%time vic_landuse.plot('alumv8')

没有任何

使用原始数据集映射输出。


http://www.hkcw.cn/article/NbvAsZtOGU.shtml

相关文章

Spring Web高保真Axure动态交互元件库

在当今快速发展的Web设计与开发领域&#xff0c;设计师和开发者们一直在寻找高效、高质量的工具来加速原型设计过程。今天&#xff0c;我要向大家介绍一款专为Web设计与开发领域量身打造的Axure交互元件集合——Spring UI Web端高保真动态交互元件库。这款元件库不仅全面且易于…

Chrome插件学习笔记(二)

Chrome插件学习笔记&#xff08;二&#xff09; 参考文章&#xff1a; https://developer.chrome.com/docs/extensions/reference/api/sidePanel?hlzh-cnhttps://developer.chrome.com/docs/extensions/reference/api/webRequest?hlzh-cnhttps://developer.chrome.com/docs/e…

判断质数的基础方法

判断一个数是否为质数&#xff1a;基础方法(运算效率较慢) 另一种运用API来提高运算效率&#xff1a; 以下是添加了详细注释的代码版本&#xff0c;并优化了部分逻辑&#xff1a; package test;public class test5 {public static void main(String[] args) {//判断一个数是否…

列表单独展开收起同时关闭其余子项的问题优化

如图所示&#xff0c;当在列表中&#xff0c;需要分别单独点开子选项时&#xff0c;直接这样用一个index参数判断即可&#xff0c;非常简单方便&#xff0c;只需要满足点开当前index,然后想同index用null值自动关闭即可

java25

1.可变参数 2.集合工具类Collections 3.综合练习 集合嵌套&#xff1a; 4.不可变集合 JDK9以后才能用 这个静态方法名是of&#xff0c;返回值是List<E>,是泛型方法。 JDK10以后的简化版&#xff1a; 5.Stream流 爽一下&#xff1a; 简化后的: 注意&#xff1a;stream.ma…

中方:南南合作始终是对外合作优先方向

当地时间5月30日,联合国南南合作基金30周年纪念活动在纽约联合国总部举行。中国常驻联合国代表傅聪在活动致辞中表示,中方高度赞赏基金支持的务实合作成果。中方表示,始终坚定支持联合国发展支柱,始终坚定支持真正的多边主义,始终将南南合作作为对外合作的优先方向。中方指…

在线博客系统【测试报告】

&#x1f552; 一. 项目背景 由于纸质笔记容易丢失&#xff0c;携带不变&#xff0c;为了方便自己学习的过程中记录笔记&#xff0c;特开发了这个博客系统。这个系统后端采用 SpringBoot MyBatis SpringMVC &#xff1b;前端使用Html CSS JS&#xff1b;数据库使用的是Mysq…

近期手上的一个基于Function Grap(类AWS的Lambda)小项目的改造引发的思考

函数式Function是云计算里最近几年流行起来的新的架构和模式&#xff0c;因为它不依赖云主机&#xff0c;非常轻量&#xff0c;按需使用&#xff0c;甚至是免费使用&#xff0c;特别适合哪种数据同步&#xff0c;数据转发&#xff0c;本身不需要保存数据的业务场景&#xff0c;…

C++ - 模板(一) #泛型编程 #函数模板 #类模板

文章目录 前言 一、泛型编程 二、函数模板 1、函数模板的概念 2、函数模板的格式 3、函数模板的原理 4、函数模板的实例化 1、隐式实例化&#xff1a; 2、显式实例化&#xff1a; 5、模板参数的匹配原则 三、类模板 1、类模板的定义格式 2、类模板的实例化 总结 …

智能制造全场景数字化解决方案

制造企业数字化转型面临的挑战 数智化转型已成为中国制造业高质量发展的关键战略。面对全球制造业格局调整&#xff0c;如何快速构建覆盖全业务流程的可视化应用&#xff0c;通过数据驱动的方式为企业经营管理、预警监测、质量管控、决策支持提供全面支撑&#xff0c;是企业面…

Vue-收集表单信息

收集表单信息 Input label for 和 input id 关联, 点击账号标签 也能聚焦 input 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>表单数据</title><!-- 引入Vue --><scrip…

篮球分组问题讨论

1 问题概述 问题&#xff1a;有5支球队在同一块场地上进行单循环赛,共要进行10场比赛。下表是一个赛程安排&#xff0c;有些队觉得不公平。研究以下问题 A B C D E 每两场比赛间相隔场次数 A X 1 9 3 6 1, 2, 2 B 1 X 2 5 8 0, 2, 2 C 9 2 X 7 10 4…

成都鼎讯--通信干扰设备功能全解析

在现代电子战与通信对抗领域&#xff0c;一款高性能的通信干扰设备是掌握电磁频谱主动权的关键。本文将深入解析一款先进的通信干扰设备&#xff0c;其凭借多频段覆盖、多通道并行、多样化调制方式及灵活供电等特性&#xff0c;成为部队、科研院所等机构在电磁对抗训练与研究中…

vscode中让文件夹一直保持展开不折叠

vscode中让文件夹一直保持展开不折叠 问题 很多小伙伴使用vscode发现空文件夹会折叠显示, 让人看起来非常难受, 如下图 解决办法 首先打开设置->setting, 搜索compact Folders, 去掉勾选即可, 如下图所示 效果如下 看起来非常爽 ! ! !

中国城市间地理距离矩阵(2024)

1825 中国城市间地理距离矩阵(2024) 数据简介 中国城市间地理距离矩阵数据集&#xff0c;通过审图号GS(2024)0650的中国城市地图在Albers投影坐标系中进行计算得出矩阵表格&#xff0c;单位为KM&#xff0c;方便大家研究使用。 中国城市地理距离矩阵数据通过计算城市中心距离…

Linux中的shell脚本

什么是shell脚本 shell脚本是文本的一种shell脚本是可以运行的文本shell脚本的内容是由逻辑和数据组成shell脚本是解释型语言 用file命令可以查看文件是否是一个脚本文件 file filename 脚本书写规范 注释 单行注释 使用#号来进行单行注释 多行注释 使用 : " 注释内容…

20250530-C#知识:抽象类、抽象方法、接口

C#知识&#xff1a;抽象类、抽象方法、接口 在开发过程中接口一般用得较多&#xff0c;程序框架往往定义一堆接口规范&#xff0c;然后程序员自己写逻辑来实现接口功能。掌握接口的知识还是很有必要的。 1、抽象类 用abstract关键字修饰的类不能用来实例化对象可以包含抽象方法…

韩国首尔一地铁车厢内遭纵火 乘客被紧急疏散

当地时间5月31日8时47分左右,韩国首尔地铁5号线一辆列车车厢内起火,乘客随后被紧急疏散。据初步调查,火灾原因为有人纵火,嫌疑人已被抓获。目前暂无人员伤亡报告。受火灾事件影响,该地铁线路部分区段一度暂停运行,首尔市交通部门10时13分通报,事故处理已经完毕,暂停运行…

跨平台浏览器集成库JxBrowser 支持 Chrome 扩展程序,高效赋能 Java 桌面应用

JxBrowser 是 TeamDev 开发的跨平台库&#xff0c;用于在 Java 应用程序中集成 Chromium 浏览器。它支持 HTML5、CSS3、JavaScript 等&#xff0c;具备硬件加速渲染、双向 Java 与 JavaScript 连接、丰富的事件监听等功能&#xff0c;能处理网页保存、打印等操作&#xff0c;助…

聊聊网络变压器的浪涌等级标准是怎样划分的呢?

Hqst盈盛&#xff08;华强盛&#xff09;电子导读&#xff1a;聊聊网络变压器的浪涌等级标准是怎样划分的呢&#xff1f; 在和做防雷产品的客户的深度沟通网络变压器产品选型中发现&#xff1a;客户对网络变压器的浪涌等级划分也很希望有更深的了解&#xff0c;今天就这个问题和…