Python3之cartopy+matplotlib绘图

1 篇文章 0 订阅
1 篇文章 0 订阅

matplotlib官网
气象绘图参考网站
色标
地图选择器
ChinaMap
主要库cartopy绘制地图、matplotlib绘图
matplotlib 是从MATLAB启发而创建的,这俩的命令几乎一模一样,所以概念基本完全相同,可参考MATLAB官方文档

关键概念
Axes (笛卡尔坐标区):
Axis (坐标轴)
Subplot (子图)
Plot (线图)
Figure (图窗)

绘图安装的库

conda install -c conda-forge numpy scipy pandas xarray geopandas matplotlib cartopy scikit-image metpy cfgrib
cartopy需要0.18.0conda install -c conda-forge cartopy=0.18.0

 import matplotlib.pyplot as plt

Figure创建窗口,类似于画板,Axes/Subplot创建子图,类似于画纸。所有的绘画只能在子图上进行。plt表示当前子图,若没有就创建一个子图
Figure:面板(图),matplotlib中的所有图像都是位于figure对象中,一个图像只能有一个figure对象。
Subplot:子图,figure对象下创建一个或多个subplot对象(即axes)用于绘制图像。
配置参数:
axex: 设置坐标轴边界和表面的颜色、坐标刻度值大小和网格的显示
figure: 控制dpi、边界颜色、图形大小、和子区( subplot)设置
font: 字体集(font family)、字体大小和样式设置
grid: 设置网格颜色和线性
legend: 设置图例和其中的文本的显示
line: 设置线条(颜色、线型、宽度等)和标记
patch: 是填充2D空间的图形对象,如多边形和圆。控制线宽、颜色和抗锯齿设置等。
savefig: 可以对保存的图形进行单独设置。例如,设置渲染的文件的背景为白色。
verbose: 设置matplotlib在执行期间信息输出,如silent、helpful、debug和debug-annoying。
xticks和yticks: 为x,y轴的主刻度和次刻度设置颜色、大小、方向,以及标签大小。

1、坐标轴曲线

    x = np.arange(-5, 5, 0.1)
    y = x * 3
    fig = plt.figure() # 1个窗口简化写法
    # fig = plt.figure(num=1, figsize=(15, 8),dpi=80)     #详细写法,设置大小,分辨率
    ax1 = fig.add_subplot(2,1,1)  # 同fig.add_subplot(211)通过fig添加子图,参数:行数,列数,第几个。1个可省略
    # 括号里面的值前两个是轴域原点坐标(从左下角计算的),后两个是显示坐标轴的长度。
    ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) #add_axes()生成子图的灵活性更强,完全可以实现add_subplot()方法的功能
	# ax2 = fig.add_subplot(2,1,2)  #通过fig添加子图,参数:行数,列数,第几个。1个可省略
	# ax1 = fig.add_subplot(111, facecolor='r') #设置背景颜色
    plt.plot(x, y) # 画图
    plt.scatter(x, y, c='r') # 设置颜色
    plt.xlabel('X Axis') #设置x轴名称 ax1.set_xlabel
    plt.ylabel('Y Axis') #设置Y轴名称 ax1.set_ylabel
    plt.title('this is a demo') # 设置标题
    plt.xlim((-5, 5)) # 设置横轴范围 ax1.set_xlim 可略,默认x,y 所有值范围
    plt.ylim((-15, 15)) # 设置纵轴范围 ax1.set_ylim 可略
    plt.savefig('d:/f.png') # 保存图片,plt.savefig('aa.jpg', dpi=400, bbox_inches='tight') dpi分辨率,bbox_inches子图周边白色空间的大小
    # 左右下上4个轴
    # 设置轴的位置
    ax1.spines['left'].set_position('center')
    # 设置轴的颜色
    ax1.spines['right'].set_color('none')
    # 设置轴的位置
    ax1.spines['bottom'].set_position('center')
    # 设置轴的颜色
    ax1.spines['top'].set_color('none')
    # 显示网格。which参数的值为major(只绘制大刻度)、minor(只绘制小刻度)、both,默认值为major。axis为'x','y','both'
    ax1.grid(b=True, which='major', axis='both', alpha=0.5, color='skyblue', linestyle='--', linewidth=2)
    # ax1.set_xticks([])  # 去除坐标轴刻度
    ax1.set_xticks((-5, -3, -1, 1, 3, 5))  # 设置坐标轴刻度
    ax1.text(2.8, 7, r'y=3*x')  # 指定位置显示文字,plt.text()
    axes1 = plt.axes([.2, .3, .1, .1], facecolor='y')  # 在当前窗口添加一个子图,rect=[左, 下, 宽, 高],是使用的绝对布局,不和以存在窗口挤占空间
    axes1.plot(x, y)  # 在图上画子图
    ax1.annotate('important point', xy=(2, 6), xytext=(3, 1.5),  # 添加标注,参数:注释文本、指向点、文字位置、箭头属性
                              arrowprops=dict(facecolor='black', shrink=0.05),)
    plt.show() #所有窗口运行

	ax.invert_yaxis() # 反转y轴	

2、绘制轮廓

1、 类似于等高线(等值线) matplotlib.pyplot.contour
# 高斯滤波,K为黑色轮廓
cs = ax.contour(dat.latitude.values, dat.level.values,
                            gaussian_filter(dat.values, 2), colors='k')
2、填充轮廓(色斑图) contourf
ax.contourf(abn.latitude.values, abn.level.values,
                             abn.values, extend='both', levels=level_abn,
                             cmap=cmap_abn, norm=norm_abn)

3、风杆图

        default_barb_style = {'length': 5,
                              'sizes': {'emptybarb': 0.25, 'spacing': 0.2, 'height': 0.5},
                              'barb_increments': {'half': 2, 'full': 4, 'flag': 20},
                              'flagcolor': 'grey'
                              }
		ax.barbs(lon, lat, u, v, transform=ccrs.PlateCarree(), **default_barb_style)

4、色标

import matplotlib.pyplot as plt

	# norm = mpl.colors.Normalize(vmin=-10, vmax=10)
	lvs = np.arange(-10, 11, 1)
    cf = ax.contourf(lon_var, lat_var,
                             2 * dat_a.to(units('delta_degC/sec')) * 1e4, extend='both',
                             levels=lvs, cmap=plt.get_cmap('RdBu_r'), # norm=norm,
                             transform=ccrs.PlateCarree())
    cax = add_axes(fig, ax_provision)
    cb = fig.colorbar(cf, cax=cax, extend='both', fraction=0.03,
                              extendfrac='auto', extendrect=True, drawedges=True)
    cb.set_ticks(lvs) # 设置色标刻度
    cb.ax.tick_params(labelsize=14)

norm :用于规范化–设置颜色条最大最小值
RdBu_r是RdBu色带的倒转

5、设置y轴比例 matplotlib.axes.Axes.set_yscale

# 仅绘制正值 正整数 int序列
ax.set_yscale('log') # 默认值:'clip'

b=蓝色 g=绿色 r=红色 y=黄色 c=青色 k=黑色 m=洋红色 w=白色

6、10的-4次方描述

f'$10^{{-4}}$'

7、中文显示问题

import matplotlib
# 指定默认字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei'] 
matplotlib.rcParams['font.family'] ='sans-serif'
# 解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False 

查看centos是否有中文

fc-list :lang=zh #fc-list :lang=zh family
>>> import matplotlib
>>> matplotlib.matplotlib_fname()
'/data/software/anaconda3/envs/py36/lib/python3.6/site-packages/matplotlib/mpl-data/matplotlibrc'

字体目录

/data/software/anaconda3/envs/py36/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/

当前字体种类

	from matplotlib import font_manager
    for font in font_manager.fontManager.ttflist:
        print(font.name, '-', font.fname)

注意:matplotlib版本影响字体属性

			[l.set_family("Times New Roman") for l in cb.ax.yaxis.get_ticklabels()]
            #gl.xlabel_style = {'size': 14, 'fontfamily': 'Times New Roman'}
            gl.xlabel_style = {'size': 14, 'family': 'Times New Roman'}
            gl.ylabel_style = {'size': 14, 'family': 'Times New Roman'}

注: https://mathsyouth.github.io/2019/06/12/macos-matplotlib

Cartopy

1、安装Cartopy库0.18.0,必须的库Shapely、pyshp

conda install -c conda-forge cartopy=0.18.0
import matplotlib.pyplot as plt
import cartopy.crs as ccrs

plt.figure(figsize=(6, 3))
ax = plt.axes(projection=ccrs.PlateCarree(central_longitude=180))
ax.coastlines(resolution='110m')
ax.gridlines()

可以运行即可
2、下载地图数据 http://www.naturalearthdata.com/downloads/
有三种分辨率的shape地图数据,分别下载三种分辨率中的physical数据中的Coastline和Land数据,
如:ne_10m_coastline.zip,解压后copy到文件夹C:\Users\Administrator.local\share\cartopy\shapefiles\natural_earth\physical
运行1中的程序后,程序会自动创建physical文件夹,默认使用110m分辨率
下载最新版本失败,就下载历史版本
:如果想使用自己的地图,比如我有一个带我国法定边界的地图shape文件,名为:World.shp、World.shx、World.dbf、World.prj,重新命名为10m_coastline或10m_land文件(这里要根据该shape文件是line型还是polygon型),替换原目录下的shape文件,画图时使用scale为10m即调用到了自己的地图

色斑图示例

import os
import logging
from pathlib import Path

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import font_manager
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
from matplotlib import cm
import geopandas as gpd

import config

MODULE_NAME = os.path.split(__file__)[-1].split(".")[0]
logger = logging.getLogger(f'module.utils.{MODULE_NAME}')
gdf = gpd.GeoDataFrame.from_file(os.path.join(config.JSON_ROOT, 'shandong', 'shandong.json'))
plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = ['SimHei', 'DejaVu Sans', 'Microsoft YaHei', 'TimesNewRoman', 'Arial']
plt.rcParams['axes.unicode_minus'] = False

font_dirs = [os.path.join(config.STATIC_PATH, 'font'), ]
font_files = font_manager.findSystemFonts(fontpaths=font_dirs)
if hasattr(font_manager.fontManager, 'addfont') and callable(font_manager.fontManager.addfont):
    [font_manager.fontManager.addfont(font) for font in font_files]
else:
    font_list = font_manager.createFontList(font_files)
    font_manager.fontManager.ttflist.extend(font_list)


def run():
    micaps4 = '/test/2021012510'
    time = Path(micaps4).name
    file = open(micaps4, mode='rt', encoding='gbk')
    tmp = file.readlines()
    row = int(tmp[0].strip().split()[16])  # 行数
    column = int(tmp[0].strip().split()[15])  # 列数
    min_lat = float(tmp[0].strip().split()[13])
    max_lat = float(tmp[0].strip().split()[14])
    min_lon = float(tmp[0].strip().split()[11])
    max_lon = float(tmp[0].strip().split()[12])
    lat_step = float(tmp[0].strip().split()[10])
    lon_step = float(tmp[0].strip().split()[9])
    logger.debug(f'micaps4 :{row, column, min_lat, max_lat, min_lon, max_lon, lat_step, lon_step}')
    lons = np.linspace(min_lon, max_lon, column)
    lats = np.linspace(min_lat, max_lat, row)
    tmp.pop(0)
    grid_data = np.zeros((row, column))
    for i in range(0, row):
        aa = tmp[i].strip().split()
        for j in range(len(aa)):
            grid_data[i][j] = float(aa[j])
    logger.debug(f'plot region: {(min_lon, max_lon, min_lat, max_lat)}')

    fig = plt.figure(dpi=150)
    ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree())
    ax.set_extent((min_lon, max_lon, min_lat, max_lat), crs=ccrs.PlateCarree())
    # ax.coastlines(linewidth=0.5) #边界

    gridlines_style = {'draw_labels': True, 'linestyle': '--', 'alpha': 0.7}

    gl = ax.gridlines(
        ylocs=np.linspace(min_lat, max_lat, 1),
        xlocs=np.linspace(min_lon, max_lon, 1),
        **gridlines_style
    )
    gl.xlabels_top = False  # 关闭顶端的经纬度标签 gl.top_labels = False
    gl.ylabels_right = False  # 关闭右侧的经纬度标签 gl.right_labels = False
    gl.xformatter = LONGITUDE_FORMATTER  # x轴设为经度的格式
    gl.yformatter = LATITUDE_FORMATTER  # y轴设为纬度的格式
    name_station = {"济南": [117, 36.65]}
    for key, value in name_station.items():  # 打印站点
        ax.scatter(value[0], value[1], marker='.', s=60, color="k", zorder=3)
        ax.text(value[0] - 0.07, value[1] + 0.03, key, fontsize=7, color="k")
    title_main = f'山东省{time} 时温度色斑图'
    title_sub = f"副标题xxx"
    ax.set_title(f'{title_main} \n {title_sub}', fontsize=18)
    ax.set_title(f'阈值: ', loc='right', fontsize=16)
    ax.add_geometries(gdf['geometry'], crs=ccrs.PlateCarree(), facecolor='', edgecolor='#2B2B2B')
    # ax.add_geometries(gdf['geometry'][0], crs=ccrs.PlateCarree(), facecolor='', edgecolor='#2B2B2B') #仅显示济南市
    cf = ax.contourf(lons, lats, grid_data,
                     transform=ccrs.PlateCarree(),
                     cmap=cm.get_cmap('bwr'))
    cb = fig.colorbar(cf, orientation='horizontal', shrink=0.8)
    cb.ax.tick_params(labelsize=14)
    [l.set_family("Times New Roman") for l in cb.ax.yaxis.get_ticklabels()]
    gl.xlabel_style = {'size': 14, 'family': 'Times New Roman'}
    gl.ylabel_style = {'size': 14, 'family': 'Times New Roman'}
    [i.set_linewidth(2) for i in ax.spines.values()]

    file_name = f'{time}.png'
    save_file = Path(config.ROOT_PATH) / 'png' / 'seban' / file_name
    if not save_file.parent.exists():
        save_file.parent.mkdir(parents=True)
    fig.savefig(save_file, dpi=100)

错误

1、linux运行py弹窗:需要Xmanager软件来处理X11转发请求
import matplotlib
matplotlib.use('Agg') #使用非交互式后端,避免创建窗口
import matplotlib.pyplot as plt  # matplotlib.use('Agg')必须在本句执行前运行

参考:
https://www.zhihu.com/question/51745620
https://www.jianshu.com/p/da385a35f68d
https://scitools.org.uk/cartopy/docs/latest/matplotlib/advanced_plotting.html
http://bbs.06climate.com/forum.php?mod=viewthread&tid=33601&extra=page%3D1

2、Reinstalling the application may fix this problem. 已放弃(吐核)

通过strace python xxx.py跟踪

stat("/data/software/anaconda3/envs/py36/bin/qt.conf", {st_mode=S_IFREG|0775, st_size=201, ...}) = 0
stat("/data/software/anaconda3/envs/py36/bin/qt.conf", {st_mode=S_IFREG|0775, st_size=201, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=405, ...}) = 0
stat("/opt/anaconda1anaconda2anaconda3/plugins", 0x7fffc834d1a0) = -1 ENOENT (No such file or directory) ##注意该处,路径错误
lstat("/data", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/data/software", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/data/software/anaconda3", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/data/software/anaconda3/envs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/data/software/anaconda3/envs/py36", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat("/data/software/anaconda3/envs/py36/bin", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
stat("/data/software/anaconda3/envs/py36/bin", {st_mode=S_IFDIR|0755, st_size=12288, ...}) = 0
stat("/data/software/anaconda3/envs/py36/bin/platforms/.", 0x7fffc834d1d0) = -1 ENOENT (No such file or directory)
open("/opt/anaconda1anaconda2anaconda3/qtlogging.ini", O_RDONLY|O_CLOEXEC) = -1 ENOENT (No such file or directory)
stat("/root/.config/QtProject/qtlogging.ini", 0x7fffc834d100) = -1 ENOENT (No such file or directory)
stat("/etc/xdg/QtProject/qtlogging.ini", 0x7fffc834d100) = -1 ENOENT (No such file or directory)
open("/dev/tty", O_RDONLY|O_CLOEXEC)    = 4
fcntl(4, F_SETFD, FD_CLOEXEC)           = 0
close(4)                                = 0
write(2, "This application failed to start"..., 155This application failed to start because it could not find or load the Qt platform plugin "xcb"
in "".

Reinstalling the application may fix this problem.
) = 155
rt_sigprocmask(SIG_UNBLOCK, [ABRT], NULL, 8) = 0
tgkill(159944, 159944, SIGABRT)         = 0
--- SIGABRT {si_signo=SIGABRT, si_code=SI_TKILL, si_pid=159944, si_uid=0} ---
+++ killed by SIGABRT (core dumped) +++
已放弃(吐核)

缺少PyQt5库

"qt.qpa.screen: QXcbConnection: C"..., 75qt.qpa.screen: QXcbConnection: Could not connect to display localhost:10.0
解决方案很简单:
export DISPLAY=':0.0'
如果不行的话则尝试
export DISPLAY=':1.0'或export DISPLAY=':2.0'
至于为何时1.0或2.0或0.0,
可以在终端执行:
echo ${DISPLAY}
显示的是什么配置成什么就行了

3、matplotlib错误ValueError: Expected 2-dimensional array, got 1

#ax.add_geometries(gdf['geometry'], crs=ccrs.PlateCarree(), facecolor='', edgecolor='#2B2B2B')
ax.add_geometries(gdf['geometry'], crs=ccrs.PlateCarree(), facecolor='none', edgecolor='#2B2B2B')

  • 5
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,很高兴为您解答。在学习Cartopy的第二步中,我们将探索如何在地上添加标记和注释。 首先,我们需要导入CartopyMatplotlib的相关库: ``` import cartopy.crs as ccrs import matplotlib.pyplot as plt ``` 接下来,我们将创建一个带有注释和标记的地。这里我们以美国为例: ``` # 创建一个以美国为中心的地 ax = plt.axes(projection=ccrs.PlateCarree()) ax.set_extent([-130, -60, 20, 50], crs=ccrs.PlateCarree()) # 添加州边界线 states_provinces = cfeature.NaturalEarthFeature( category='cultural', name='admin_1_states_provinces_lines', scale='50m', facecolor='none') ax.add_feature(states_provinces, edgecolor='gray') # 添加湖泊和河流 lakes = cfeature.NaturalEarthFeature( category='physical', name='lakes', scale='50m', facecolor='none') ax.add_feature(lakes, edgecolor='blue') rivers = cfeature.NaturalEarthFeature( category='physical', name='rivers_lake_centerlines', scale='50m', facecolor='none') ax.add_feature(rivers, edgecolor='blue') # 添加城市标记 ax.plot(-75, 40, 'bo', markersize=7, transform=ccrs.PlateCarree()) ax.text(-75.5, 40.5, 'New York', transform=ccrs.PlateCarree()) # 添加注释 ax.text(-129, 22, 'USA', horizontalalignment='left', transform=ccrs.Geodetic()) ax.text(-100, 25, 'Great Lakes', horizontalalignment='center', transform=ccrs.PlateCarree()) ax.text(-98, 37, 'Mississippi River', horizontalalignment='center', transform=ccrs.PlateCarree()) plt.show() ``` 这段代码会绘制一个以美国为中心的地,同时添加州边界线、湖泊和河流的标记和注释。其中,城市标记是以蓝色圆点的形式添加的,注释则是以文本的形式添加的。 这就是在Cartopy中添加标记和注释的基本方法。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值