爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 205472|回复: 177

[经验总结] python读取shp地图文件

  [复制链接]

新浪微博达人勋

发表于 2021-2-6 22:09:03 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
python读取shp地图文件

为了小白画图初体验四,得先做一些铺垫,也是自己踩的坑,然后学的习。其中一个基础就是怎么读取shp文件。
shp文件一般有三个,.shp.dbf.shx,存放的就是地图信息,更直接一点的就是点的信息,由点构成线,由线构成多边形。而读取出来的点信息是以经纬度表示的。
气象绘图能涉及的一般是shapefile库和Basemap库,两个都可以读取shp文件。其实Basemap还是依赖shapefile
这里主要介绍shapefile库读取的方法,和Basemap库出现“utf-8”错误的解决方法。

shapefile库读取shp文件
概述


import shapefile
sf = shapefile.Reader('Zhejiang_province')
shapes = sf.shapes()


这是读取shp文件的基本操作,shapes里面存放的就是地图信息类的数组。,里面一个或者多个shapefile类

sf = shapefile.Reader('Zhejiang_province')
shapes = sf.shapes()
pts = shapes[0].points
prt =shapes[0].parts


上面的文件是浙江省省界,就一个文件

sf = shapefile.Reader("country1")
for shape_rec in sf.shapeRecords():
pts = shape_rec.shape.points#边界点
prt = shape_rec.shape.parts


上面的文件是国家界,就多个类,每一个存放了每个国界的信息
下面以单一的文件给大家作介绍,方便理解,多文件无非就是写个循环,加个判断。

简单介绍

浙江省省界文件

sf = shapefile.Reader('Zhejiang_province')

shapes = sf.shapes()

pts = shapes[0].points

prt =shapes[0].parts


.points里面存放所有点的信息,每个点用(x,y)表示,其实就是所表示区域的边界点,代码里读出的就是浙江省的所有边界点,用经纬度来表示位置。这里存在一个问题,那就是以浙江省为例,有舟山群岛,所有点的坐标不连续,其实相当于许多小区域的组合,但是.points里面不管这些,只会表示点,咱们画图来看一下


import shapefile

import matplotlib.pyplot as plt

sf = shapefile.Reader('Zhejiang_province')

shapes = sf.shapes()

codes = []

pts = shapes[0].points

x,y = zip(*pts)#把经纬度分别给到x,y

fig = plt.figure(figsize=[12,18])

ax = fig.add_subplot(111)

ax.plot(x, y, '-', lw=1, color='k')


plt.show()

22.png

可以看出,画完陆地去画岛的时候很生硬,直接扯过去了(因为用的是plot,如果是散点图不会画成这样,但我们不需要散点)。
这里涉及了另一个知识点

shapefile.Reader类属性

包含有4个属性:数据类型(shapeType),代表该"几何数据"对象的数据类型(点,shapeType=1,线,shapeType=3,多边形,shapeType=5);数据范围(bbox),只针对多点数据,代表该"几何数据"对象的边界范围;数据块(parts),只针对线或者多边形,代表该"几何数据"对象各个块的第一个点的索引;点集(points),代表该"几何数据"对象的所有点坐标。

点集(points):这个已经介绍过了

数据类型(shapeType):是shp文件内部按什么状态存放,以上面浙江省界例子来看是多边形shapeType=5,即区块

sf = shapefile.Reader('Zhejiang_province')

shapes = sf.shapes()

print(shapes[0].shapeType)

数据范围(bbox):就是经纬度的最大最小值,四个,上下左右
重点说一下
数据块(parts):既然上文提到了shp文件所描绘的边界会出现断开的现象,那从哪开始断开呢,就在这个属性里面记录。parts属性是一个列表,记录了每个区块第一个点的索引值,即下标。
气象绘图目前精确一点的mask方法就是利用parts,points结合matplotlib中的路径功能来做mask。

气象绘图利用shp文件做掩膜

先放代码,还是以浙江省界为例

fig = plt.figure(figsize=[12,18])

ax = fig.add_subplot(111)

sf = shapefile.Reader('Zhejiang_province')

shapes = sf.shapes()

codes = []

pts = shapes[0].points#边界点

prt = list(shapes[0].parts) + [len(pts)]#区块起始索引

for i in range(len(prt) - 1):

    codes += [Path.MOVETO]#点移动

    codes += [Path.LINETO] * (prt[i+1] - prt -2)#画线

    codes += [Path.CLOSEPOLY]#这块画完,循环结束,下一块

clip = Path(pts, codes)#利用数据和路径生成一个画图动作

clip = PathPatch(clip, transform=ax.transData)#再加入ax的变换

prt的含义:上文已经说过了parts的意义,设想一下,两块区域的的起始坐标中间夹的不就是一块区域的所有坐标吗,但是最后一块区域没有结束值,所有加了[len(pts)],这就是最后一个点的索引。

for循环的作用:建立一个绘图路径,利用区块起始点的索引生成一个画图动作

最后生成的clip就是我们需要的掩膜mask,在合适的位置配合下列代码完成掩膜白化效果:

cs = data.plot.contourf(ax=ax,levels=levels,cbar_kwargs=cbar_kwargs, cmap='Spectral_r')

for contour in cs.collections:

        contour.set_clip_path(clip)

大家可以不用理解原理,只需要明白,怎么读取shp文件,找到你需要的边界坐标点(points)和(parts),把他们带入其中,执行这个过程就可以了。

下一个问题:Basemap库出现“utf-8”错误的解决方法

Basemap库还是很好用的,但是有些朋友肯定出现过这个问题

m.readshapefile('Zhejiang_province','Zhejiang Map',color='k',linewidth=1.2)

当我们执行这条命令时报错

File "C:\ProgramData\Miniconda3\lib\site-packages\shapefile.py", line 104, in u

    return v.decode(encoding, encodingErrors)


UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe8 in position 2: invalid continuation byte

这是shapefile需要读取文件得“utf-8”编码的缘故,解决方法,进入一下路径(作者的电脑,大家相应寻找)C:\ProgramData\Miniconda3\Lib\site-packages
找到shapefile.py文件,复制一份(防止操作失误),然后在shapefile.py文件的第104行做修改

#原来的

return v.decode(encoding, encodingErrors)

#修改为


return v.decode('latin-1', encodingErrors)

这样编译就可以通过了,如果以后碰到utf-8的出错了记得改回来。

最后还是提醒大家文章是以单个shapes[0].points为例的,有一部分shp内部有很多个,记得做循环,筛选你需要的
以我自己画的图结束吧

还是建议大家前往CSDN论坛看代码,能舒服很多:htps://blog.csdn.net/weixin_42372313/article/details/113728014

Zhengjiang_mask_T2m.png






示例地图文件.rar

1.59 MB, 下载次数: 353, 下载积分: 金钱 -5

评分

参与人数 1金钱 +10 收起 理由
Rainch + 10 赞一个!

查看全部评分

密码修改失败请联系微信:mofangbao

新浪微博达人勋

 楼主| 发表于 2021-12-21 22:19:48 | 显示全部楼层
quentin011099 发表于 2021-12-21 17:32
你好,四川的地市和县域地图有吗?,谢谢!

发给你了
密码修改失败请联系微信:mofangbao
回复 支持 1 反对 0

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-12-20 21:52:06 | 显示全部楼层
心中有党 发表于 2021-12-20 14:50
云南省地市和县域地图有吗?麻烦给我发一份 十分感谢

给你了

评分

参与人数 1金钱 +20 贡献 +2 收起 理由
心中有党 + 20 + 2 20金钱,2贡献奉上

查看全部评分

密码修改失败请联系微信:mofangbao
回复 支持 1 反对 0

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-2-6 22:15:24 | 显示全部楼层
大家需要各自省份的shp文件可以留言,作者给你发过去
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2021-2-7 08:41:35 | 显示全部楼层
我也和楼主一样尝试了很多shp文件,但我属于尝试出来了但不知道原理。感谢楼主分享
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-2-7 12:49:18 | 显示全部楼层
likailing2008 发表于 2021-2-7 08:41
我也和楼主一样尝试了很多shp文件,但我属于尝试出来了但不知道原理。感谢楼主分享

共同学习
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2021-2-8 11:31:18 | 显示全部楼层
{:eb502:}{:eb502:}{:eb502:}
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-2-8 12:33:41 | 显示全部楼层
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2021-2-28 16:40:40 | 显示全部楼层
你好,江西的地市和县域地图有吗?78498062@qq.com,谢谢!
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-3-1 08:52:06 来自手机 | 显示全部楼层
qinhantang10 发表于 2021-02-28 16:40
你好,江西的地市和县域地图有吗?78498062@qq.com,谢谢!

暂时有点事,晚上发给你
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

发表于 2021-3-1 08:57:37 | 显示全部楼层
求一个各省的shp~邮箱:3305622519@qq.com
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2021-3-1 16:20:47 | 显示全部楼层
qinhantang10 发表于 2021-2-28 16:40
你好,江西的地市和县域地图有吗?,谢谢!

已发邮箱,查收一下
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表