爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 12604|回复: 2

[经验总结] matplotlib 图片根据shp文件裁剪

[复制链接]

新浪微博达人勋

发表于 2020-5-27 11:41:25 | 显示全部楼层 |阅读模式

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

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

x
本帖最后由 饕餮之影 于 2020-5-27 11:41 编辑

最近对画的EC图做裁剪,根据中国区域的shp文件裁剪中国区域的,遇到点问题记录一下:
def clip_region(sf, ax):

    for shape_rec in sf.shapeRecords():
        vertices = []
        codes = []
        pts = shape_rec.shape.points
        prt = list(shape_rec.shape.parts) + [len(pts)]
        for i in range(len(prt) - 1):
            for j in range(prt, prt[i + 1]):
                vertices.append((pts[j][0], pts[j][1]))
            codes += [ mpl.path.Path.MOVETO]
            codes += [ mpl.path.Path.LINETO] * (prt[i + 1] - prt - 2)
            codes += [ mpl.path.Path.CLOSEPOLY]
        clip = mpl.path.Path(vertices, codes)
        clip = mpl.patches.PathPatch(clip, transform=ax.transData)

    return clip, vertices

wind_clevs  = [0.01, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 100]
wind_colors = ["#FFFFF0", "#F0F4D2", "#E9F49F", "#ABCF63", "#E3EE0F", "#FFEE00", "#FFEE83", "#F4D280","#EEA647", "#E68D3B", "#DC7D3B", "#F0013B", "#E955A4", "#9C70A9", "#6370F7", "#8097FF", "#8FB4FF", "#B7CAFF"]

U = np.random.randint(30, size=(481, 721))
V = np.random.randint(30, size=(481, 721))

fig = plt.figure(figsize=(16, 8))
ax  = fig.add_axes([0.1, 0.1, 0.7, 0.7])
map = Basemap(projection='cyl',
              llcrnrlon=60,
              llcrnrlat=0,
              urcrnrlon=150,
              urcrnrlat=60)

map.drawcoastlines()    # 绘制海岸线
map.drawcountries()     # 绘制国界
parallels = np.arange(0.,60,10.)
map.drawparallels(parallels,labels=[1,0,0,0],fontsize=10) # 绘制纬线

meridians = np.arange(60.,150.,10.)
map.drawmeridians(meridians,labels=[0,0,0,1],fontsize=10) # 绘制经线

cmap = mpl.colors.ListedColormap(wind_colors)
norm = mpl.colors.BoundaryNorm(wind_clevs, ncolors=cmap.N, clip=False)

lats = np.arange(0, 60.125, 0.125)[::-1]
lons = np.arange(60, 150.125,0.125)
x, y = np.meshgrid(lons, lats)

wind_10m = np.sqrt(U**2 + V**2)
im = plt.contourf(x, y, wind_10m, norm=norm, cmap=cmap, alpha=1)
sf = shapefile.Reader(shpname + '.shp', encoding='ISO-8859-1')
clip, vertices = clip_region(sf, ax)

for cour in im.collections:
   cour.set_clip_path(clip)

for x in plt.gca().get_children():
    if type(x) == mpl.patches.FancyArrowPatch:
        x.set_clip_path(clip)

fig.colorbar(strm.lines)
plt.show()

画图使用的数据是随机产生的,画图是使用contourf,裁剪前后的图片:
使用contour画等高线是一样的。这个比较好操作网上可以查询,但是我使用streamplot画流线图出现了剪裁问题:
strm = plt.streamplot(x, y, U, V, color=U, linewidth=1, cmap=cmap, norm=norm, arrowsize=1)
这个返回有两个对象是strm.lines和strm.arrows,是保存线和箭头的,

使用strm.lines.set_clip_path(clip),strm.arrows.set_clip_path(clip)裁剪之后:
线条被裁了但是箭头还存在,查看连个对象返回的路径,get_paths()发现两个的坐标系不一样,lines是CompositeGenericTransform(复合转换),arrows是IdentityTransform(原地转换),我以为是这个问题导致的,于是在clip_region中收集区域边界点的时候 vertices.append(ax.transData.transform(pts[j][0], pts[j][1])),还是没有效果,后来搜到发现箭头是属于
matplotlib.patches.FancyArrowPatch,无论怎么对strm.arrows操作都没有效果,我们可以使用另一个方法
for x in gca().get_children():    if type(x) == matplotlib.patches.FancyArrowPatch:        x.set_clip_path(clip)
这样就可以达到效果了,结果图:



contourf裁剪之后的

contourf裁剪之后的

streamplot裁剪之前的

streamplot裁剪之前的

contourf裁剪之前的

contourf裁剪之前的

streamplot裁剪

streamplot裁剪

streamplot裁剪之后的

streamplot裁剪之后的
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2020-5-27 13:14:56 | 显示全部楼层
很给力,这个是流线的剪裁
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

新浪微博达人勋

 楼主| 发表于 2020-5-27 14:12:38 | 显示全部楼层
平流层的萝卜 发表于 2020-5-27 13:14
很给力,这个是流线的剪裁

嗯嗯,对风场流线图的剪裁
密码修改失败请联系微信:mofangbao
回复 支持 反对

使用道具 举报

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

本版积分规则

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

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

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