python--对站点数据做EOF并做插值绘制填色图

简介: 最近,师弟在学习使用python复现毕设论文,正好之前没有处理过站点数据,也没咋用过EOF,特此记录下使用python处理站的数据的过程。

前言



最近,师弟在学习使用python复现毕设论文,正好之前没有处理过站点数据,也没咋用过EOF,特此记录下使用python处理站的数据的过程。


  • 读取站点资料数据
  • 对站点数据进行插值,插值到规则网格上
  • 绘制EOF第一模态和第二模态的空间分布图
  • 绘制PC序列


关于插值,这里主要提供了两个插值函数,一个是一般常用的规则网格插值:

  • griddata


另一个是metpy中的:

  • inverse_distance_to_grid()


本来只是测验一下不同插值方法,但是发现两种插值方法的结果差别很大,由于对于站点数据处理较少,所以不太清楚具体原因。如果有知道的朋友可以告知一下,不甚感谢!


本次数据存储的文件格式为.txt,读取的方法是通过pandas.read_csv()


同时,之前一直尝试使用proplot进行绘图,较长时间不用matplotlib.pyplot绘图了,也当做是复习一下绘图过程。

绘图中的代码主要通过封装函数,这样做的好处是大大减少了代码量。


导入必要的库:


from eofs.standard import Eof
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
import pandas as pd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
from metpy.interpolate import inverse_distance_to_grid


出现找不到库的报错,这里使用conda install packagename 安装一下就好


读取存储的数据:


##################### read station  data   ##########################################
path = r'D:/data.txt'
file = pd.read_csv(path,sep= "\t",
                   header=None,
                   names=['station','lat','lon','year','data'],
                   na_values=-99.90)
data = file['data'].to_numpy()
lon  = file['lon'].to_numpy()
lat  = file['lat'].to_numpy()
year = file['year'].to_numpy()
station = file['station'].to_numpy()
year_max = np.max(year)
year_min = np.min(year)
year_range = np.arange(year_min,year_max+1,1)
data_all = data.reshape(70,53)
lon_all = lon.reshape(70,53)/100
lat_all = lat.reshape(70,53)/100   
lon_real = lon_all[:,0]
lat_real = lat_all[:,0]


这里将读取的数据全部转为array格式,方便查看以及后续处理。本来存储的文件中是没有相关的经度、纬度、站点、时间的名称的,这里我是自己加在上面方面数据读取的。

本次处理的数据包含70个站点,53年


插值


#####################   interp data   ##########################################
### interp data to target grid
### set target grid
lon_target = np.arange(115,135.5,0.5)
lat_target = np.arange(38,55.5,0.5)
x_t, y_t = np.meshgrid(lon_target, lat_target)
z = np.zeros((len(year_range),lat_target.shape[0],lon_target.shape[0]))
for i in range(len(year_range)):
    print(i)
    # z[i] = inverse_distance_to_grid(lon_real,lat_real,
    #                                 data_all[:,i],
    #                                 x_t,y_t, r=15, min_neighbors=3)
    z[i] = griddata((lon_real,lat_real),
                                    data_all[:,i],
                                    (x_t,y_t),method='cubic')


这里显示了使用griddata()的插值过程,metpy的过程注释掉了,需要测试的同学之间取消注释即可。

注意点:插值过程需要先设置目标的插值网格


EOF处理:


#计算纬度权重
lat_new = np.array(lat_target)
coslat=np.cos(np.deg2rad(lat_new))
wgts = np.sqrt(coslat)[..., np.newaxis]
#创建EOF分解器
solver=Eof(z,weights=wgts)
eof=solver.eofsAsCorrelation(neofs=2)
#此处的neofs的值是我们需要的空间模态数
pc=solver.pcs(npcs=2,pcscaling=1)#方差
var=solver.varianceFraction(neigs=2)


这里没啥好说的,需要几个模态自由选择即可


定义绘图函数并绘图:


##################### def  plot function ##########################################
def contourf(ax,i,level,cmap):
    extents = [115,135,35,55]
    ax.set_extent(extents, crs=proj)
    ax.add_feature(cfeature.LAND, edgecolor='black',facecolor='silver',
                    )
    ax.add_feature(cfeature.LAKES, edgecolor='black',facecolor='w',
                    )
    ax.add_feature(cfeature.BORDERS)
    xtick = np.arange(extents[0], extents[1], 5)
    ytick = np.arange(extents[2], extents[3], 5)
    ax.coastlines()
    tick_proj = ccrs.PlateCarree()
    c = ax.contourf(lon_target,lat_target,eof[i], 
                    transform=ccrs.PlateCarree(),
                    levels=level,
                    extend='both',
                    cmap=cmap)
    ax.set_xticks(xtick, crs=tick_proj)
    ax.set_xticks(xtick,  crs=tick_proj)
    ax.set_yticks(ytick, crs=tick_proj)
    ax.set_yticks(ytick, crs=tick_proj)
    ax.xaxis.set_major_formatter(LongitudeFormatter())
    ax.yaxis.set_major_formatter(LatitudeFormatter())
    plt.yticks(fontproperties='Times New Roman',size=10)
    plt.xticks(fontproperties='Times New Roman',size=10)
    ax.tick_params(which='major', direction='out', 
                    length=4, width=0.5, 
                 pad=5, bottom=True, left=True, right=True, top=True)
    ax.tick_params(which='minor', direction='out', 
                  bottom=True, left=True, right=True, top=True)
    ax.set_title( 'EOF'+str(i),loc='left',fontsize =15)
    return c
def p_line(ax,i):
    ax.set_title('pc'+str(i)+'',loc='left',fontsize = 15)
    # ax.set_ylim(-3.5,3.5)
    ax.axhline(0,linestyle="--")
    ax.plot(year_range,pc[:,i],color='blue')
    ax.set_ylim(-3,3)
#####################  plot ##########################################
fig = plt.figure(figsize=(8, 6), dpi=200) 
proj = ccrs.PlateCarree()
contourf_1 = fig.add_axes([0.02,0.63,0.5,0.3],projection=proj)
c1=contourf(contourf_1,0,np.arange(0.7,1,0.05),plt.cm.bwr)
plot_1 = fig.add_axes([0.45,0.63,0.5,0.3])
p_line(plot_1,0)
contourf_2 = fig.add_axes([0.02,0.15,0.5,0.3],projection=proj)
c2= contourf(contourf_2,1,np.arange(-0.5,0.6,0.1),plt.cm.bwr)
plot_2 = fig.add_axes([0.45,0.15,0.5,0.3],)
p_line(plot_2,1)
cbposition1 = fig.add_axes([0.16, 0.55, 0.22, 0.02])
cb = fig.colorbar(c1,cax=cbposition1,
             orientation='horizontal',format='%.1f')
cb.ax.tick_params(which='both',direction='in')
cbposition2=fig.add_axes([0.16, 0.08, 0.22, 0.02])
cb2 = fig.colorbar(c2,cax=cbposition2,
             orientation='horizontal',format='%.1f')
cb2.ax.tick_params(which='both',direction='in')
plt.show()



这里将大部分重复的绘图代码,进行了封装,通过封装好的函数进行调用,大大简洁了代码量。相关的封装过程之前也有讲过,可以翻看之前的记录。


展示结果


使用griddata的绘图结果:


9fc7b76ff91e46f08d5cd45fd79c9943.png


使用metpt插值函数的结果:


image.png


附上全部的绘图代码:


# -*- coding: utf-8 -*-
"""
Created on Fri Sep 23 17:46:42 2022
@author: Administrator
"""
from eofs.standard import Eof
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
import pandas as pd
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
from cartopy.mpl.ticker import LongitudeFormatter, LatitudeFormatter
from metpy.interpolate import inverse_distance_to_grid
##################### read station  data   ##########################################
path = r'D:/data.txt'
file = pd.read_csv(path,sep= "\t",
                   header=None,
                   names=['station','lat','lon','year','data'],
                   na_values=-99.90)
data = file['data'].to_numpy()
lon  = file['lon'].to_numpy()
lat  = file['lat'].to_numpy()
year = file['year'].to_numpy()
station = file['station'].to_numpy()
year_max = np.max(year)
year_min = np.min(year)
year_range = np.arange(year_min,year_max+1,1)
data_all = data.reshape(70,53)
lon_all = lon.reshape(70,53)/100
lat_all = lat.reshape(70,53)/100   
lon_real = lon_all[:,0]
lat_real = lat_all[:,0]
#####################   interp data   ##########################################
### interp data to target grid
### set target grid
lon_target = np.arange(115,135.5,0.5)
lat_target = np.arange(38,55.5,0.5)
x_t, y_t = np.meshgrid(lon_target, lat_target)
z = np.zeros((len(year_range),lat_target.shape[0],lon_target.shape[0]))
for i in range(len(year_range)):
    print(i)
    # z[i] = inverse_distance_to_grid(lon_real,lat_real,
    #                                 data_all[:,i],
    #                                 x_t,y_t, r=15, min_neighbors=3)
    z[i] = griddata((lon_real,lat_real),
                                    data_all[:,i],
                                    (x_t,y_t),method='cubic')
#计算纬度权重
lat_new = np.array(lat_target)
coslat=np.cos(np.deg2rad(lat_new))
wgts = np.sqrt(coslat)[..., np.newaxis]
#创建EOF分解器
solver=Eof(z,weights=wgts)
eof=solver.eofsAsCorrelation(neofs=2)
#此处的neofs的值是我们需要的空间模态数
pc=solver.pcs(npcs=2,pcscaling=1)#方差
var=solver.varianceFraction(neigs=2)
##################### def  plot function ##########################################
def contourf(ax,i,level,cmap):
    extents = [115,135,35,55]
    ax.set_extent(extents, crs=proj)
    ax.add_feature(cfeature.LAND, edgecolor='black',facecolor='silver',
                    )
    ax.add_feature(cfeature.LAKES, edgecolor='black',facecolor='w',
                    )
    ax.add_feature(cfeature.BORDERS)
    xtick = np.arange(extents[0], extents[1], 5)
    ytick = np.arange(extents[2], extents[3], 5)
    ax.coastlines()
    tick_proj = ccrs.PlateCarree()
    c = ax.contourf(lon_target,lat_target,eof[i], 
                    transform=ccrs.PlateCarree(),
                    levels=level,
                    extend='both',
                    cmap=cmap)
    ax.set_xticks(xtick, crs=tick_proj)
    ax.set_xticks(xtick,  crs=tick_proj)
    ax.set_yticks(ytick, crs=tick_proj)
    ax.set_yticks(ytick, crs=tick_proj)
    ax.xaxis.set_major_formatter(LongitudeFormatter())
    ax.yaxis.set_major_formatter(LatitudeFormatter())
    plt.yticks(fontproperties='Times New Roman',size=10)
    plt.xticks(fontproperties='Times New Roman',size=10)
    ax.tick_params(which='major', direction='out', 
                    length=4, width=0.5, 
                 pad=5, bottom=True, left=True, right=True, top=True)
    ax.tick_params(which='minor', direction='out', 
                  bottom=True, left=True, right=True, top=True)
    ax.set_title( 'EOF'+str(i),loc='left',fontsize =15)
    return c
def p_line(ax,i):
    ax.set_title('pc'+str(i)+'',loc='left',fontsize = 15)
    # ax.set_ylim(-3.5,3.5)
    ax.axhline(0,linestyle="--")
    ax.plot(year_range,pc[:,i],color='blue')
    ax.set_ylim(-3,3)
#####################  plot ##########################################
fig = plt.figure(figsize=(8, 6), dpi=200) 
proj = ccrs.PlateCarree()
contourf_1 = fig.add_axes([0.02,0.63,0.5,0.3],projection=proj)
c1=contourf(contourf_1,0,np.arange(0.7,1,0.05),plt.cm.bwr)
plot_1 = fig.add_axes([0.45,0.63,0.5,0.3])
p_line(plot_1,0)
contourf_2 = fig.add_axes([0.02,0.15,0.5,0.3],projection=proj)
c2= contourf(contourf_2,1,np.arange(-0.5,0.6,0.1),plt.cm.bwr)
plot_2 = fig.add_axes([0.45,0.15,0.5,0.3],)
p_line(plot_2,1)
cbposition1 = fig.add_axes([0.16, 0.55, 0.22, 0.02])
cb = fig.colorbar(c1,cax=cbposition1,
             orientation='horizontal',format='%.1f')
cb.ax.tick_params(which='both',direction='in')
cbposition2=fig.add_axes([0.16, 0.08, 0.22, 0.02])
cb2 = fig.colorbar(c2,cax=cbposition2,
             orientation='horizontal',format='%.1f')
cb2.ax.tick_params(which='both',direction='in')
plt.show()


总结


metpy的插值函数好处在于可以自由填充整个绘图区域,但是感觉griddata函数的插值结果更加符合预期,虽然也有点怪怪的。


这两个插值函数造成的差异目前不太清楚,仅记录处理数据以及绘图的过程,有清楚原因的大佬记得在评论区补充一下!非常感谢啦!


            一个努力学习python的ocean er
              水平有限,欢迎指正!!!
              欢迎评论、收藏、点赞、转发、关注。
            关注我不后悔,记录学习进步的过程~~


相关文章
|
3天前
|
数据处理 Python
数据变形记:Python转换技巧大公开,轻松玩转数据魔方!
在数据处理领域,数据变形是连接原始数据与洞察的桥梁。本文通过电商用户购买行为数据集的案例,展示了Python强大的数据处理能力。我们将购买日期转换为日期类型,计算每位用户的总花费,并对商品价格应用折扣,最终将杂乱的数据转化为有序、有价值的信息。通过Pandas库,我们实现了从简单类型转换到复杂数值计算的全过程,揭示了数据变形的无限可能。
13 1
|
3天前
|
数据采集 存储 JavaScript
构建您的第一个Python网络爬虫:抓取、解析与存储数据
【9月更文挑战第24天】在数字时代,数据是新的金矿。本文将引导您使用Python编写一个简单的网络爬虫,从互联网上自动抓取信息。我们将介绍如何使用requests库获取网页内容,BeautifulSoup进行HTML解析,以及如何将数据存储到文件或数据库中。无论您是数据分析师、研究人员还是对编程感兴趣的新手,这篇文章都将为您提供一个实用的入门指南。拿起键盘,让我们开始挖掘互联网的宝藏吧!
|
1天前
|
Python
Python 中如何循环某一特定列的所有行数据
Python 中如何循环某一特定列的所有行数据
|
2天前
|
数据采集 数据挖掘 数据处理
数据清洗,不只是清洁!Python教你如何挖掘数据中的隐藏价值!
在数据驱动的时代,数据被视为企业的核心资产。然而,这些宝贵的数据往往伴随着噪声、缺失值、异常值等问题,如同未经雕琢的璞玉,需要精心打磨才能展现出其内在的价值。数据清洗,这一看似简单的预处理过程,实则蕴含着挖掘数据深层价值的无限可能。今天,就让我们借助Python的力量,一同探索如何通过数据清洗来发现数据中的隐藏宝藏。
13 1
|
1天前
|
JSON JavaScript 前端开发
6-19|Python数据传到JS的方法
6-19|Python数据传到JS的方法
|
1天前
|
Python
python如何循环某一特定列的所有行数据
python如何循环某一特定列的所有行数据
|
2天前
|
数据挖掘 Python
Python数据挖掘编程基础
本章介绍了Python数据挖掘编程的基础知识,涵盖Python入门所需的命令、判断与循环、函数、库导入等内容,并重点讲解了数据分析预处理和建模常用库。通过学习基本运算、数据结构、字符串操作等,帮助读者快速掌握Python语言,为后续数据挖掘工作打下坚实基础。例如,通过代码`a=3`进行赋值,利用`a*3`执行乘法运算,使用`a**3`计算幂,以及通过对字符串的拼接和分割操作,展示Python的强大功能。
11 0
|
1天前
|
存储 人工智能 数据挖掘
Python编程入门:从基础到实战
【9月更文挑战第26天】 在这篇文章中,我们将一起探索Python编程的奇妙世界。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供有价值的信息和技巧。我们将从Python的基本语法开始,然后逐步深入到更复杂的主题,如函数、类和模块。最后,我们将通过一个实际的项目来应用我们所学的知识。让我们一起开始这段Python编程之旅吧!
|
2天前
|
数据采集 人工智能 数据挖掘
Python编程入门:从基础到实战的快速指南
【9月更文挑战第25天】本文旨在为初学者提供一个简明扼要的Python编程入门指南。通过介绍Python的基本概念、语法规则以及实际案例分析,帮助读者迅速掌握Python编程的核心技能。文章将避免使用复杂的专业术语,而是采用通俗易懂的语言和直观的例子来阐述概念,确保内容的可读性和实用性。
|
1天前
|
Python
探索Python编程中的装饰器魔法
【9月更文挑战第26天】在Python的世界里,装饰器就像是一把瑞士军刀,小巧而功能强大。它们让代码更简洁、可维护性更强。本文将通过实际示例,带你领略装饰器的魔力,从基础到进阶,一步步揭开它的神秘面纱。
9 2