shp与数据库(插入数据)

前言

正文

geopandas与shp文件创建表和录入数据

解释一下上面的代码

查询cd2表的geometry字段

查看一下表

前一篇博客的冲突

问题的解决

POLYGON与MUTLIPOLYGON的说明

解决问题的代码

修改表的创建

shapefile和sqlalchemy插入数据

数据库查询

最后


前言

 前一篇讲解了通过shp创建表,shp文件与数据库(创建表)-CSDN博客 ,

后来感觉写麻烦了。因为可以用geopandas来创建表和写入数据,非常简单。但是笔者还是想根据自己的想法继续写下去。

正文

geopandas与shp文件创建表和录入数据

如果使用geopandas,创建表和录入数据都显得很简单,代码如下。

import geopandas as gpd
import pandas as pd
from sqlalchemy import create_engine
from geoalchemy2 import Geometry, WKTElement
engine = create_engine('postgresql+psycopg2://username:password@localhost/arcgis')

# 读取Shapefile文件
gdf = gpd.read_file('成都/成都.shp')
# 几何数据转换为 Well-Known Text (WKT) 格式
gdf['geometry'] = gdf['geometry'].apply(lambda x: WKTElement(x.wkt, srid=4326))
# 存入数据库
gdf.to_sql('cd2', engine, if_exists='replace', index=False,dtype={'geometry': Geometry('GEOMETRY', srid=4326)})

# repalce 替代表

 运行结果如下。

解释一下上面的代码

gdf = gpd.read_file('成都/成都.shp')

读取shp文件,但通过geopandas读取shp文件和通过shapefile读取shp二者是有区别的,

因为geopands是在pandas的基础上建立的库,很明显二者的数据类型一定是不一样的,可以打印一下。

gdf = gpd.read_file('成都/成都.shp')
print(gdf.dtypes)

 结果如下。

其中最关键的数据类型是geometry,后面会提及,打印一下geometry

gdf = gpd.read_file('成都/成都.shp')
print(gdf.geometry)

 结果如下

可以看到既有PLOYGON,也有MULTIPOLYGON。正因为如此,如果最后一行的代码写dtype的geometry写PLOYGON,将会报错,写MULTIPOLYGON可以运行,报错如下。

但类型可以是点、线等其他,不知道是什么类型,所以写个最大的类型是GEOMETRY。

当然可以使用如下代码,将MULTIPOLYGON分解成PLOYGON。

gdf = gdf.explode(index_parts=True)

对于如下行代码

gdf['geometry'] = gdf['geometry'].apply(lambda x: WKTElement(x.wkt, srid=4326))

这一步将 GeoDataFrame 中的几何数据转换为 Well-Known Text (WKT) 格式,这是一种可以被 SQLAlchemy 和许多数据库系统识别的地理空间数据格式。

不写,也会报错,报错如下。

虽然只有几行代码,但一不小心就会报错,但是geopandas还是非常可以的。

查询cd2表的geometry字段

需要添加与空间数据有关的扩展

-- 添加扩展
create extension postgis;

查询语句 

-- 查询cd2表的geometry字段
select  St_astext(geometry) from cd2;

结果如下

查看一下表

通过datagrip查看建表的语句,如下图

从图中可以看出geometry的类型

geometry(Geometry, 4326)

和前面代码相对应。可以用,

有些字段加上引号,字段不统一,对于引号,可以去除掉,在上面代码的基础上,添加如下代码。

gdf.columns=gdf.columns.str.lower()

把列名变成小写,当然也可以转下划线,看个人喜好吧,笔者猜测应该有专门的方法解决这个,笔者也不知道。

再次运行结果如下。

前一篇博客的冲突

对于前一篇博客,shp文件与数据库(创建表)-CSDN博客,

从上面用geopandas创建表的过程中,最关键的一步,就是geometry的类型是判断,可以直接写最大的类型Geometry,不管shp文件中有什么数据,POINT还是POLYGON等,都在Geometry中。

前一篇博客,笔者创造的表的geometry是POLYGON类型的,如下图所示。

笔者之所以会认为是PLOYGON类型的,是根据如下代码的结果

import shapefile
shp=shapefile.Reader('成都/成都.shp')
for i in shp.shapes():
    print(i)

结果如下。

类型是POLYGON,但数据中既有POLYGON又有MUTLIPOLYGON,怎么办,怎么确定那个数据是POLYGON,那个是MUTLIPOLYGON???还是全部都是POLYGON?全部都是MUTLIPOLYGON?

问题的解决

POLYGON与MUTLIPOLYGON的说明

POLYGON:表示一个单独的多边形,它由一个或多个线性环组成。第一个线性环定义了多边形的外部边界,其余的线性环(如果有的话)定义了多边形的内部孔洞。  
MULTIPOLYGON:表示一组多边形,每个多边形都是独立的,可以有自己的外部边界和内部孔洞。

简单是说,MultiPoylgon由多个Plygon构成,Plygon之间的空间关系是相离,因此MultiPolygon并没有外环

解决问题的代码

笔者经过多次的探索,问了多种ai,最后解决了,一言难尽,一言难尽,直接说最后的结果吧,看代码。

import shapefile
# 第三方库
from shapely.geometry.polygon import LinearRing
# 闭合的线性环(Linear Ring)对象,用于判断是否为环
shp=shapefile.Reader('成都/成都.shp')
for i in shp.shapes():
    ring=LinearRing(i.points)
    if ring.is_ring:
        print('POLYGON')
    else:
        print('MULTIPOLYGON')

有环则是POLYGON,为True

无环则是MUTLIPOLYGON,为False

打印结果如下

POLYGON
POLYGON
MULTIPOLYGON
POLYGON
POLYGON
POLYGON
POLYGON
POLYGON
POLYGON
MULTIPOLYGON
MULTIPOLYGON
POLYGON
POLYGON
POLYGON
MULTIPOLYGON
POLYGON
MULTIPOLYGON
POLYGON
POLYGON
MULTIPOLYGON

修改表的创建

根据前面的说明,可以得知。geometry的类型,需要判断环,结论如下。

1、如果全是有环的,则设为PLOYGON

2、如果全是无环的,则设为MUTLIPOLYGON

3、如果二者都有,则设为GEOMETRY

表的创建的代码如下。

from geoalchemy2 import Geometry
# Geometry 空间数据类型
from sqlalchemy.schema import CreateTable
from sqlalchemy.orm import declarative_base
from sqlalchemy import Table, Column, Integer, VARCHAR, create_engine, BigInteger, Numeric, DATE, Boolean
from dataclasses import dataclass, fields
from shapely.geometry.polygon import LinearRing
import shapefile

Base = declarative_base()


@dataclass
class Shp2Postgres:
    shp_path: str
    table_name: str = 'shp'
    pg_db: str = 'arcgis'
    engine: create_engine = create_engine(f'postgresql+psycopg2://username:password@localhost/{pg_db}')
    file: shapefile.Reader = None
    words: list = None
    shape_name: str = None
    """
    :param shp_path: shp文件路径
    :param table_name: 表名
    :param pg_db: 数据库名
    :param engine: 数据库引擎
    :param file: shp文件
    :param words: shp文件字段
    :param shape_name: shp文件类型
    :param ShpTable: shp文件对应的表
    """

    def __post_init__(self):
        self.file = shapefile.Reader(self.shp_path)
        self.words = self.file.fields[1:]
        self.shape_name = self.file.shapeTypeName
        self.set_geometry_type()

        class ShpTable(Base):
            __tablename__ = self.table_name
            id = Column(Integer(), primary_key=True, autoincrement=True, nullable=False, comment='id')
            geometry = Column(Geometry(geometry_type=self.shape_name, srid=4326), comment='空间信息')

        self.ShpTable = ShpTable
        self.add_column()

    def set_geometry_type(self):
        """
        设置几何类型
     
        :return:
        """
        if self.shape_name == 'POLYGON':
            POLYGON = 0
            MULTIPOLYGON = 0
            for i in self.file.shapes():
                ring = LinearRing(i.points)
                if ring.is_ring:
                    POLYGON += 1
                else:
                    MULTIPOLYGON += 1
            if POLYGON == 0:
                self.shape_name = 'MULTIPOLYGON'
            elif MULTIPOLYGON == 0:
                self.shape_name = 'POLYGON'
            else:
                self.shape_name = 'GEOMETRY'
        else:
            pass

    def add_column(self):
        """
        添加字段
        :return:
        """
        for field in self.words:
            name = field[0]
            _type = field[1]
            length = field[2]
            decimal = field[3]
            match _type:
                case 'N':
                    _type = BigInteger()
                case 'C':
                    _type = VARCHAR(length)
                case 'F':
                    _type = Numeric(length, decimal)
                case 'L':
                    _type = Boolean()
                case 'D':
                    _type = DATE()
                case 'M':
                    _type = VARCHAR(255)
                case _:
                    _type = VARCHAR(255)
            setattr(self.ShpTable, name, Column(_type, comment=name, name=name, quote=False))

    def execute(self):
        """
        执行创建
        :return:
        """
        # 执行创建
        Base.metadata.create_all(self.engine)
        # 打印创建表的sql语句
        table = CreateTable(self.ShpTable.__table__).compile(self.engine)
        print(table)


Shp2Postgres('成都/成都.shp', table_name='cd').execute()

打印语句如下。

CREATE TABLE cd (
	id SERIAL NOT NULL, 
	geometry geometry(GEOMETRY,4326), 
	adcode BIGINT, 
	name VARCHAR(80), 
	childrenNu BIGINT, 
	level VARCHAR(80), 
	parent VARCHAR(80), 
	subFeature BIGINT, 
	PRIMARY KEY (id)
)

设置类型为GEOMETRY。

shapefile和sqlalchemy插入数据

直接该出代码,当然比较麻烦。(0.o)

import shapefile
from sqlalchemy import create_engine, Table, MetaData, insert
from sqlalchemy.orm import Session
from sqlalchemy.exc import NoSuchTableError
from geoalchemy2 import Geometry
from attrs import define, Factory, fields
from shapely.geometry import shape
from logging import StreamHandler, getLogger, DEBUG
from colorlog import ColoredFormatter
from typing import List, Optional
import sys

engine = create_engine('postgresql+psycopg2://username:1234@localhost/arcgis')


@define
class InsertData:
    shp_path: str
    table_name: str
    session: Session = None
    shp_file: shapefile.Reader = None
    table: Table = None
    record_data: List[dict] = []
    """
    :param shp_path: shp文件路径
    :param table_name: 表名
    :param session: 数据库会话
    :param shp_file: shp文件
    :param table: shp文件对应的表
    :param record_data: 记录数据
    """

    @property
    def log(self):
        """
        日志的配置
        :return:
        """
        colors = {
            'DEBUG': 'bold_red',
            'INFO': 'bold_blue',
            'WARNING': 'bold_yellow',
        }
        logger = getLogger(__file__)
        stream_handler = StreamHandler()
        logger.setLevel(DEBUG)
        color_formatter = ColoredFormatter(
            fmt='%(log_color)s %(asctime)s %(filename)s  %(funcName)s line:%(lineno)d %(levelname)s : %(message)s',
            datefmt='%Y-%m-%d %H:%M:%S',
            log_colors=colors
        )
        stream_handler.setFormatter(color_formatter)
        logger.addHandler(stream_handler)
        return logger

    def __set_table(self):

        """
        获取表
        :return:
        """
        try:
            self.table = Table(self.table_name, MetaData(), autoload_with=engine)
            self.log.info('获取表成功')
        except NoSuchTableError as e:
            self.log.error('获取表失败,请检查表名是否正确')
            return None

    def start(self):
        self.shp_file = shapefile.Reader(self.shp_path)
        self.session = Session(bind=engine)
        self.__set_table()
        if self.table is None:
            return
        words = self.shp_file.fields[1:]
        word_names = [word[0].lower() for word in words]
        for record in self.shp_file.shapeRecords():
            record_dict = {word_names[i]: record.record[i] for i in range(len(word_names))}
            # 几何数据转换为 Well-Known Text (WKT) 格式
            record_dict['geometry'] = shape(record.shape).wkt
            self.record_data.append(record_dict)
        self.insert()

    def insert(self):
        """
        插入数据
        :return:
        """
        self.session.execute(insert(self.table), self.record_data)
        self.session.commit()
        self.log.info('插入成功')

运行结果

数据库查询

-- 查询cd2表的geometry字段
select  St_astext(geometry) from cd;

结果

ok。

最后

插入数据还是用geopands简单。

不能确定代码一定正确,有错再修改。

后面再把数据库中的数据变成shp文件。

后面可以加上UI界面。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

与AI合作 -- 写一个modern c++单例工厂

目录 前言 提问 bard给出的答案 AI答案的问题 要求bard改进 人类智能 AI VS 人类 前言 通过本文读者可以学到modern C单例模式工厂模式的混合体,同时也能看到:如今AI发展到了怎样的智能程度?怎样让AI帮助我们快速完成实现头脑中的想法&…

【hcie-cloud】【17】华为云Stack灾备服务介绍【灾备方案概述、备份解决方案介绍】【上】

文章目录 前言灾备方案概述灾备的定义灾备的重要性故障和灾难对业务连续性带来的挑战灾备系统的衡量指标RTO与RPO分析 灾备等级标准数据中心容灾解决方案全景图云灾备服务总结架构华为云Stack灾备服务总览 备份解决方案介绍云备份服务介绍备份服务架构介绍云备份服务组件功能介…

界面原型设计工具有哪些?看看这9个

界面原型设计是现代设计师必备的技能之一。在设计数字产品或应用程序时,界面原型是将概念转化为具体可交互界面的重要步骤。对于新手小白来说,选择一款易于上手且功能强大的界面原型设计工具至关重要。本文将介绍 9 个常用的界面原型设计工具&#xff0c…

计算机体系结构动态调度(计分板及Tomasulo)学习记录

1.动态调度核心思想:允许就绪指令越过前方停顿指令,提前进入运行(乱序执行) 就绪指令指不存在资源冲突、操作数已就绪的指令,例如,计分板算法使用计分板来实现,Tomasulo使用保留站来实现&#…

苹果电脑交互式原型设计软件Axure RP 9 mac特色介绍

Axure RP 9 for Mac是一款交互式原型设计软件,使用axure rp9以最佳的方式展示您的作品,优化现代浏览器并为现代工作流程设计。同时确保您的解决方案正确完整地构建。Axure RP 9 for Mac为您整理笔记,将其分配给UI元素,并合并屏幕注…

swing快速入门(三十九)进度对话框

🎁注释很详细,直接上代码 上一篇 🧧新增内容 🧨1.模拟耗时操作 🧨2.使用计时器更新进度对话框 🎀源码: package swing31_40;import javax.swing.*; import java.awt.event.ActionEvent; import …

【debug】为什么ansible中使用command出错

碎碎念 在使用ansible执行command的时候,遇到执行会出错的command 比如执行source打算读取环境变量的时候 错误提示为: 没有那个文件或目录:source 一开始以为是错误提示有问题,一直在testrc的路径上检查,但是同样一行命令使用…

C++八股学习心得.8

1.const知道吗?解释其作用 const 修饰类的成员变量,表示成员常量,不能被修改。 const修饰函数承诺在本函数内部不会修改类内的数据成员,不会调用其它非 const 成员函数。 如果 const 构成函数重载,const 对象只能调…

聊聊 Java 集合框架中的 ArrayList

其实 Java 集合框架也叫做容器,主要由两大接口派生而来,一个是 collection,主要存放对象的集合。另外一个是Map, 存储着键值对(两个对象)的映射表。 下面就来说说 List接口,List存储的元素是有序、可重复的。其下有三个…

配置git服务器

第一步: jdk环境配置 (1)搜索【高级系统设置】,选择【高级】选项卡,点【环境变量】 (2)在【系统变量】里面,点击【新建】 (3)添加JAVA_HOME环境变量JAVA_HO…

展台搭建的基本要求

一、选址及总平面布置 展厅人流量大,对选址和总平面布置的要求如下:展厅选址应位于市内或郊区交通便利的区域。大型展览馆应有足够的群众活动广场和停车面积 ,并应有室外陈列场地。室外场地要考虑环境的绿化和美化。各功能分区之间联系方便又互不干扰。建…

实现LCM在docker之间的通信

目录 1.docker容器互联 新建网络 连接容器 2.设置环境变量 3.在两个docker之间实现通信 1.docker容器互联 新建网络 $ docker network create -d bridge test-net 连接容器 运行一个容器并连接到新建的 test-net 网络: $ docker run -itd --name lcm_1 --network tes…

极智项目 | 实战Paddle戴口罩检测

欢迎关注我的公众号 [极智视界],获取我的更多项目分享 大家好,我是极智视界,本文来介绍 实战 Paddle 戴口罩检测项目。 本文介绍的 实战 Paddle 戴口罩检测项目,提供完整的可以一键执行的项目工程源码,获取方式有两个…

AI红娘开启约会新时代;网易云音乐Agent实践探索;微软生成式AI课程要点笔记;ComfyUI新手教程;图解RAG进阶技术 | ShowMeAI日报

👀日报&周刊合集 | 🎡生产力工具与行业应用大全 | 🧡 点赞关注评论拜托啦! 👀 Perplexity 官宣 7360 万美元B轮融资,打造世界上最快最准确的答案平台 https://blog.perplexity.ai/blog/perplexity-rais…

yyds,4 个 Pandas 必备神器!

Pandas是我们日常处理表格数据最常用的包,但是对于数据分析来说,Pandas的DataFrame还不够直观。 今天我们将介绍4个和Pandas相关的Python包,可以将Pandas的DataFrame转换交互式表格,让我们可以直接在上面进行数据分析的操作。 P…

天洑软件与常州大学成立电子信息专业学位硕士研究生联合培养基地

2023年12月27日,天洑软件与常州大学微电子与控制工程学院成立电子信息专业学位硕士研究生联合培养基地,授牌及企业导师聘任仪式于常州大学西太湖校区隆重举办。天洑软件前瞻技术研究院院长张儒受邀与会。 开幕式上,微电子与控制工程学院党委书…

NUXT3学习笔记

1.邂逅SPA、SSR 1.1 单页面应用程序 单页应用程序 (SPA) 全称是:Single-page application,SPA应用是在客户端呈现的(术语称:CSR(Client Side Render)) SPA的优点 只需加载一次 SPA应用程序只需…

Docker实战08|Docker管道及环境变量识别

上一篇文章中,讲解了如何通过Go语言实现对Docker Cgroup的资源限制 具体文章可见《Docker就应该这么学-07》 有需要的小伙伴可以回顾一下。 接下来本文会详细介绍一下Docker 管道及环境变量识别 管道及环境变量识别 获取代码 git clone https://gitee.com/mjr…

SEO全自动发布外链工具源码系统:自动增加权重 附带完整的搭建安装教程

SEO全自动发布外链工具是一款基于PHP和MySQL开发的外链发布工具。它通过自动化流程,帮助站长快速、有效地发布外链,提高网站的权重和排名。该工具支持多种外链发布平台,如论坛、博客、分类信息等,可自定义发布内容和格式&#xff…

Plotly.js 热力图与折线结合

上次记录了Echarts热力图与折线图的结合,但其效果不是很自然。后又找到了Plotly.js库,发现其效果不错。在此整理下实现过程。这里面涉及到自定义工具栏、自定义工具图标等等 配置工具栏显示的工具图标 let config {locale: zh-cn, // 设置本地语…
最新文章