跟着 gma 学 Python:矢量面文件的空间绘图

news2024/11/26 0:37:52

  得益于 gdal 的强大功能,gma 继承了其对各类栅格/矢量(目前支持超过80种矢量文件格式)文件的读取支持,并在其基础上进行简化、优化等改造,以便其符合 gma 的整体建库逻辑。
  本文基于 gma 定义的矢量读取逻辑和方式,重点展示如何结合 Matplotlib,实现矢量面文件的空间绘制。

绘制思路

开始
打开文件
读取图层/要素
读取折点坐标
生成并绘制多边形
结束

gma 矢量读取逻辑介绍

  在 gma 里,所有的打开的矢量数据可分为三级,分别为 数据资源—图层—要素。一般来说,普通的矢量数据均只含一个图层(例如:shp文件等)。一些特殊的文件可能会包含多个图层,这点与含有子数据集的多维栅格类似。可通过如下代码查看支持多图层的矢量格式:

import gma
gma.config.VectorFormatInfo().MultiLayersFormats

{‘AVCBIN’, ‘CAD’, ‘DGN’, ‘DXF’, ‘EDIGEO’, ‘GML’, ‘GPKG’, ‘GPX’, ‘KML’, ‘LIBKML’, ‘MSSQLSpatial’, ‘Memory’, ‘NGW’, ‘ODBC’, ‘ODS’, ‘OSM’, ‘OpenFileGDB’, ‘PDF’, ‘PGeo’, ‘PostgreSQL’, ‘S57’, ‘SQLite’, ‘VRT’, ‘XLS’, ‘XLSX’}

层级之间的关系及应用方式如下图:

注意:在 gdal/ogr 中,Feature 下还有 Geometry(几何)这一层(类),gma 舍弃了这一部分!!

环境与数据

系统: Window 10+ (X64)
Python 版本: 3.8.8 +
gma 版本: 1.1.2 +
其他 Python 第三方库: matplotlib、numpy

试验数据: https://gma.luosgeo.com/Open/China_Province_2022.7z

  gma:地理与气象分析库。安装和详细功能帮助见:地理与气象分析库。

绘制矢量的基础代码(详询:Luo_Suppe)

  基于 gma 最小矢量数据单元 Feature 的 PlotFeature (绘制要素)是绘制矢量面的最小算法,用以被 PlotLayer (绘制图层)调用。

注意:下述代码部分内容可忽略,因为其是为后续的标注和图例等功能准备的。
注意:未体现的导入在 from XXX import * 中已经引入。

import matplotlib.patches as ptc

from functools import partial

import numpy as np

from gma.algorithm.core.dataio import *

## 注意:以下两模块会在1.1.2版本中出现(当前最新版:1.1.1)
from gma.algorithm.core.gcreate import CreatePolygon
from gma.extend.mapplot.utils import *

class PlotFeature:
    '''绘制矢量要素'''
    def __init__(self, GMAFeature, Axes, **kwargs):
            
        if isinstance(GMAFeature, Feature):
            self.GMAFeature = GMAFeature
        else:
            raise
           
        if issubclass(plt.Subplot, type(Axes)) is False:
            raise
        else:
            self.Axes = Axes
        
        plt.axis('equal')
  
        self.ELECollection = self.ELECollections()
          
    def ELECollections(self):
        '''解包多要素集合'''
        ## 本方法的目的是:将包含多个几何体的单个要素拆分,从而方便绘制
        P = self.GMAFeature.Points

        while isinstance(P[0], list):
            if isinstance(P[0][0], list):
                if isinstance(P[0][0][0], list) is False:
                    break
            P = sum(P, [])
        return P
            
    def DrawPolygon(self, FaceColor = None, EdgeColor = None, Hatch = None, LineStyle = None, LineWidth = None, ADBoundary = True, **kwargs):
        '''绘制多边形'''
        ## 清除重复的参数
        for k in ['facecolor', 'edgecolor', 'hatch', 'linestyle', 'linewidth']:
            if k in kwargs:
                kwargs.pop(k)

        XMIN, XMAX, YMIN, YMAX = [np.inf, -np.inf, np.inf, -np.inf]
        FaceColor, EdgeColor, Hatch, LineStyle, LineWidth = PlotOptions(FaceColor, EdgeColor, Hatch, LineStyle, LineWidth)

        for ELE in self.ELECollection:
            ELE = np.array(ELE)[:, :2]
            if len(ELE) < 3 or ELE[0] == []:
                continue
            
            XMIN, YMIN = np.concatenate([ELE, [[XMIN, YMIN]]], axis = 0).min(axis = 0)
            XMAX, YMAX = np.concatenate([ELE, [[XMAX, YMAX]]], axis = 0).max(axis = 0)
            
            Poly = ptc.Polygon(ELE, 
                               facecolor = FaceColor, 
                               edgecolor = EdgeColor, 
                               hatch = Hatch,
                               linestyle = LineStyle,
                               linewidth = LineWidth,
                               **kwargs)
            
            self.Axes.add_patch(Poly)
            
        if ADBoundary == True:
            self.Axes.set_xlim(XMIN - (XMAX - XMIN) * 0.05, XMAX + (XMAX - XMIN) * 0.05)
            self.Axes.set_ylim(YMIN - (YMAX - YMIN) * 0.05, YMAX + (YMAX - YMIN) * 0.05)  

class PlotLayer: 
    '''绘制矢量图层'''
    
    def __init__(self, GMALayer, Axes = None, Boundary = None, **kwargs):
        
        if isinstance(GMALayer, Layer):
            self.GMALayer = GMALayer
        else:
            raise
            
        self.BBox = self.GMALayer.Boundary
        
        if Boundary is None:    
            self.Left = self.BBox[0] - (self.BBox[2] - self.BBox[0]) * 0.05
            self.Right = self.BBox[2] + (self.BBox[2] - self.BBox[0]) * 0.05
            self.Bottom = self.BBox[1] - (self.BBox[3] - self.BBox[1]) * 0.05
            self.Top = self.BBox[3] + (self.BBox[3] - self.BBox[1]) * 0.05
        else:
            self.Left, self.Bottom, self.Right, self.Top = INITBoundary(Boundary)

            
        self.BFeature = self._CreateBGeom()
        
        if Axes is None:
            ## 根据图层范围自动调整长宽比
            X = self.Right - self.Left
            Y = self.Top - self.Bottom
            if X > Y:
                Width = 10
                Height = Y / X * Width
            else:
                Height = 10
                Width = X / Y * Height
                
            Fig = plt.figure(figsize = (Width, Height), dpi = 100)
            Axes = plt.subplot(1, 1, 1, **kwargs) 
            
        elif issubclass(plt.Subplot, type(Axes)) is False:
            raise

        self.Axes = Axes
        
        # 是否进行绘制的标志
        self.ColorOPT = []
        
        # 记录需要绘制要素的 ID
        self.DrawFeatureInfo = list(self._FeatureIterator())
 
    def _CreateBGeom(self):
        '''创建一个视图范围内的几何体'''
        ## 只绘制视图范围内的几何体,从而节约绘制时间
        Points = [[self.Left, self.Top], 
                  [self.Left, self.Bottom],
                  [self.Right, self.Bottom],
                  [self.Right, self.Top]]
        
        self.BPolygon = CreatePolygon(Points)
    
    def _FeatureIterator(self):
        '''要素迭代器'''
        i = -1
        for FID in range(self.GMALayer.FeatureCount):
            FU = self.GMALayer.GetFeature(FID)
            if FU._Geometry.Intersects(self.BPolygon):
                FEA = ogr.Feature(ogr.FeatureDefn())
                FEA.SetGeometry(FU._Geometry.Intersection(self.BPolygon))
                i = i + 1
                yield i, FID, FU, Feature(FEA)
        
    def DrawPolygon(self, FaceColor = None, EdgeColor = None, Hatch = None, LineStyle = None, LineWidth = None, **kwargs):
        '''绘制图层'''
        GetP = partial(GetPOptions, FaceColor = FaceColor, EdgeColor = EdgeColor, 
                       Hatch = Hatch, LineStyle = LineStyle, LineWidth = LineWidth)

        for i, FID, FU, FPlot in self.DrawFeatureInfo:
            
            gmp = PlotFeature(FPlot, self.Axes)
            
            FC, EC, H, LS, LW = GetP(i)
            self.ColorOPT.append([FC, EC, H, LS, LW])

            gmp.DrawPolygon(FaceColor = FC, EdgeColor = EC, Hatch = H, LineStyle = LS, LineWidth = LW, ADBoundary = False, **kwargs)

            
        self.Axes.set_xlim(self.Left, self.Right)
        self.Axes.set_ylim(self.Bottom, self.Top) 

        return self.Axes

应用及说明(详询:Luo_Suppe)

import gma
DS = gma.Open('China_Province_2022.shp')
LY = DS.GetLayer(0)

# 这里是根据 matplotlib 色带抽取颜色,也可以自己定义
from gma.extend.mapplot import plot
Colors = plot.GetColorFromCMap('jet', N = LY.FeatureCount, Alpha=1)

# 开始绘制
PlotP = PlotLayer(LY, Boundary = None)
Axes = PlotP.DrawPolygon(FaceColor = Colors,
                         EdgeColor = 'gray', 
                         Hatch = ['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'] * 10,
                         LineStyle = '-',
                         LineWidth = 1)
# 返回 matplotlib axes,可以进一步修改轴、刻度等内容,详情参考:matplotlib。                       

# 绘制部分区域
PlotP = plot.PlotLayer(LY, Boundary = [109,31,118,38])
Axes = PlotP.DrawPolygon(FaceColor = 'lightblue',
                         EdgeColor = 'gray', 
                         Hatch = None,
                         LineStyle = '-.',
                         LineWidth = None)             

注意:左右边界处有缝隙,暂不清楚问题出在哪里。

参数说明

PlotLayer(GMALayer, Axes=None, Boundary=None, **kwargs)


GMALayer: 通过 gma.Open 打开并获取的矢量图层。

Axes: matplotlib 子图,不存在则自动生成。

Boundary: 绘图范围(左、下、右、上),默认是输入矢量范围外扩 0.05 倍。

**kwargs: 自动生成 matplotlib 子图时传递给 plt.subplot 的其他参数。



PlotP.DrawPolygon(FaceColor=None, EdgeColor=None, LineStyle=None, Hatch=None, LineWidth=None, **kwargs)

FaceColor: 填充颜色。可为每个多边形分配不同的颜色。详见 matplotlib.patches.Polygon。

EdgeColor: 边界线颜色。可为每个边分配不同的颜色。详见 matplotlib.patches.Polygon。

LineStyle: 边界线线形。可为每个边分配不同的线性。详见 matplotlib.patches.Polygon。

LineWidth: 边界线线宽。可为每个边分配不同的线宽。详见 matplotlib.patches.Polygon。

Hatch: 填充纹理。可为每个多边形分配不同的纹理。详见 matplotlib.patches.Polygon。

**kwargs: 绘制多边形时传递给 matplotlib.patches.Polygon 的其他参数。

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

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

相关文章

26 CPP运算符重载

#include <iostream>using namespace std;//非成员函数重载 - class Person { public:Person() {m_score 0;m_name.clear();}void show() {cout << m_name << " " << m_score << endl;}int m_score;string m_name; };//全局重载号 vo…

毕业设计 - 基于SSH码头船只出行及配套货柜码放 管理系统【源码 + 论文】

文章目录前言一、项目设计1. 模块设计2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 java web设计项目: 基于SSH码头船只出行及配套货柜码放 管理系统 一、项目设计 1. 模块设计 对于码头日常管理来说&#xff0c;主要是码头船只的管理&#xff0c;码头信息的…

【leetcode.15】三树枝和

题目描述如上 要点分析&#xff1a; 遍历出所有的情况不难&#xff0c;难的是如果和处理重复的结果 纯暴力&#xff0b;检索的话复杂度为n3&#xff0c;最后面的三个测试点会超时 所以这里使用双指针法进行处理&#xff0c;复杂度会变为n2 算法分析&#xff1a; 为了避免…

Java+SSM家庭理财管理系统(含源码+论文+答辩PPT等)

项目功能简介: 该项目采用技术&#xff1a;SSM框架MySQL数据库Tomcat服务器&#xff0c;项目含有源码、文档、配套开发软件、软件安装教程、项目发布教程等 项目功能介绍&#xff1a; 用户分为系统管理员和普通用户两个角色&#xff0c;普通用户可自行注册登录&#xff0c;系统…

【图像处理】Hough变换人眼虹膜定位【含Matlab源码 387期】

⛄一、数字图像处理简介 图像处理基础教程链接 1 【基础教程】基于matlab图像处理&#xff08;表示方法数据结构基本格式类型转换读取点运算代数运算&#xff09;【含Matlab源码 834期】 2 【基础教程】基于matlab图像处理&#xff08;读写显示运算转换变换增强滤波分析统计&a…

计算机毕设Python+Vue学生宿舍管理系统 (程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

【遥感科学】第二章 电磁辐射和地物光谱特性

第二章 电磁辐射与地物光谱特征 一、电磁波谱与电磁辐射 1.1 磁波谱 我们说波谱波谱&#xff0c;那么什么是波&#xff0c;什么是谱呢&#xff1f;注意看&#xff0c;这个男人叫小帅 振动的传播称为波&#xff0c;那电磁波又是啥&#xff1f;啥叫电磁振动&#xff1f; 当电…

docker常用命令记录

1.docker加载镜像 sudo docker load --input rknn-toolkit-1.7.3-docker.tar.gz 2.查看镜像 sudo docker images 3.进入docker容器 sudo docker run -t -i --privileged rknn-toolkit:1.7.3 /bin/bash 4.退出容器 eixt 5.查看所有容器 sudo docker ps -a 6.开启容…

截止12.19--之前的再说,就先说一下今天的事

12/19 错怪colab 软链接实现永久 试一下我在ssh传上文件以后&#xff0c;1080卡还能不能看见了&#xff1a;能&#xff0c;得传到data里。可以在ssh上加上 ln -s 找不到GPU是镜像问题 出现找不到显卡的问题 需要换个镜像 所以速速自学docker吧&#xff0c;太被动了 加号做连…

基于AD Event日志识别黄金票据攻击

01、简介黄金票据(Golden Ticket)是基于Kerberos认证的一种攻击方式&#xff0c;常用来做域控权限维持。当攻击者获取到域内krbtgt帐户的SID和HASH&#xff0c;就可以随意伪造域内管理员用户&#xff0c;再加上域帐户krbtgt的密码基本不会更改&#xff0c;即使域管修改了密码&a…

汇编循环指令(汇编统计正负数汇编语言1到100的求和汇编求一组数最大值)

目录 LOOP指令&#xff08;重点掌握&#xff09; LOOPZ/LOOPE指令 LOOPNZ/LOOPNE指令 例题 一&#xff1a;读程序写结果 二&#xff1a;阅读程序段回答问题 三&#xff1a;读程序写结果 四:求100内的数累和 五&#xff1a;统计正数负数零 六&#xff1a;求字节单元中…

03---后端框架搭建

1、创建项目 打开Ider&#xff0c;创建springboot项目。创建页面勾选需要的依赖&#xff0c;自定义包名、存储位置等&#xff0c;然后创建项目pom依赖如下 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>…

jenkins开发相关

1、jenkins 处理系统配置中publish over ssh中的密码 主机信息数据存储在&#xff5e;/.jenkins/jenkins.plugins.publish_over_ssh.BapSshPublisherPlugin.xml文件中。 java后端如果要加密可以通过以下方法实现。 String Password "xxxx" String passwd "pr…

中科方德服务器操作系统虚拟机安装过程记录

没啥技术含量&#xff0c;就是过程中踩了一些坑&#xff0c;我做个记录&#xff0c;方便后续查阅以及其他人参考什么的。 1、新建虚拟机向导---选择典型配置 2、选择&#xff1a;稍后安装客户机操作系统 3、选择客户机操作 系统以及版本&#xff0c;中科方德服务器系统为在安装…

【LeetCode每日一题】——338.比特位计数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【题目进阶】九【时间频度】十【代码实现】十一【提交结果】一【题目类别】 动态规划 二【题目难度】 简单 三【题目编号】 338.比特位计数 四【题目描述…

IPv4 ACL访问列表简介、ACL的3种主要分类介绍与配置、以大白话介绍ACL通配符、ACL动作、定义方向、Rule序号。

3.0.0 IPv4 ACL列表&#xff08;简介、ACL分类、ACL配置、通配符&#xff09; ACL访问控制列表简介ACL的分类(华为设备)1、基本/标准ACL基本ACL编号&#xff1a;2000~2999基本ACL的作用&#xff1a;基于数据流的源地址进行匹配2、高级ACL高级ACL编号&#xff1a;3000~3999高级A…

代码随想录刷题记录day46 最长递增子序列+最长连续递增序列+最长重复子数组

代码随想录刷题记录day46 最长递增子序列最长连续递增序列最长重复子数组 300. 最长递增子序列 思想 1.dp数组的定义 dp[i]表示[0,i]区间的最长递增子序列 2.递推公式 如果num[i]>num[j];dp[i]dp[j]1 其中j从0到i-1遍历 3.初始化 所有的都初始化为1 4.遍历顺序 从…

一文读懂于Zebec生态中的潜在收益方式

随着加密市场逐渐陷入低谷&#xff0c;曾经火热的NFT、GameFi等赛道都陷入了沉寂。投资者目前很难在加密市场中获得可观的收益&#xff0c;而在整体加密市场发展局势不明朗的情况下&#xff0c;行业目前缺乏发展动力。 目前&#xff0c;以流支付为主要定位的Zebec生态&#xff…

docker-compose入门以及部署SpringBoot+Vue+Redis+Mysql(前后端分离项目)以若依前后端分离版为例

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_霸道流氓气质的博客-CSDN博客_前后端分离的项目怎么运行 上面在搭建起来前后端分离版的项目后。 如果想通过Dockerfile的方式部署项目可以参考如下。…

沃尔玛账号被冻结后如何进行申诉?

目前申请一个沃尔玛店铺并不容易&#xff0c;但仍有不少卖家因为操作不当导致账号被冻结封禁&#xff0c;这对于国内的卖家来说是巨大的损失。那么要如何避免账号被冻结&#xff0c;冻结后又该如何申诉呢&#xff1f;如何避免账号被冻结&#xff1f; 一、保证店铺表现符合平台标…