如何使用Python读取NetCDF文件并写入CSV

如何使用Python读取NetCDF文件并写入CSV,python,netcdf,Python,Netcdf,我的目标是访问netcdf文件中的数据,并以以下格式写入CSV文件 Latitude Longitude Date1 Date2 Date3 100 200 <-- MIN_SFC values --> 以下是我尝试过的: 来自netCDF4导入数据集,num2date filename=“C:/filename.nc” nc=数据集(文件名为'r',格式为'NETCDF4') 打印nc变量 打印“变量列表” 对于nc变量中的var: 打印变量、变量单

我的目标是访问netcdf文件中的数据,并以以下格式写入CSV文件

Latitude  Longitude Date1  Date2  Date3
100       200       <-- MIN_SFC values -->
以下是我尝试过的:
来自netCDF4导入数据集,num2date
filename=“C:/filename.nc”
nc=数据集(文件名为'r',格式为'NETCDF4')
打印nc变量
打印“变量列表”
对于nc变量中的var:
打印变量、变量单位、变量形状
#获取坐标变量
lats=nc.变量['纬度][:]
lons=nc.变量['longitude'][:]
sfc=nc.变量['Min\u sfc'][:]
times=nc.变量['time'][:]
#转换日期,如何存储日期只带走时间?
打印“转换日期”
单位=nc.变量['time'].单位
日期=num2日期(时间[:],单位=单位,日历=365天)
#打印日期中日期的[dates.strftime(“%Y%m%d%H”)]
标题=['纬度','经度']
#将日期附加到标题字符串
对于d in日期:
打印d
header.append(d)
#写入文件
导入csv
将open('Output.csv','wb')作为csvFile:
outputwriter=csv.writer(csvFile,分隔符=',')
outputwriter.writerow(标题)
对于lat,拉链中的lon(lats,lons):
outputwriter.writerow([lat,lon])
#关闭输出文件
csvFile.close()
#关闭netcdf

nc.close()
不确定您还有什么问题,这看起来不错。我确实看到:

# convert date, how to store date only strip away time?
 print "Converting Dates"
 units = nc.variables['time'].units
 dates = num2date (times[:], units=units, calendar='365_day')
现在,您将日期作为python datetime对象

 #print [dates.strftime('%Y%m%d%H') for date in dates]
如果希望将它们作为字符串,则需要这样做——但如果只需要一天,请删除%H:

日期字符串=[日期中日期的日期.strftime(“%Y%m%d”)]

如果希望年、月、日作为数字,datetime对象具有以下属性:

年,月,日

对于sfc变量,它是一个3-d数组,因此要获得特定值,可以执行以下操作:

sfc[时间指数、纬度指数、经度指数]

作为三维文件,有多种方法可以将其写入csv文件,但我猜您可能需要以下内容:

对于时间索引,枚举中的时间(时间): #取出当时的数据 数据=sfc[时间索引:,:] #将日期写入文件(可能) # .... 现在循环“行” 对于数据中的行: outputwriter.writerow([str(val)表示第行中的val])


或者类似的东西……

我会将数据加载到Pandas中,这有助于分析和绘制时间序列数据,以及写入CSV

下面是一个实际的工作示例,它从全球预测模型数据集中提取了指定lon,lat位置的波高时间序列

注意:这里我们访问一个OPeNDAP数据集,这样我们就可以从远程服务器提取所需的数据,而无需下载文件。但是netCDF4对于移除OPeNDAP数据集或本地NetCDF文件的效果完全相同,这是一个非常有用的功能

import netCDF4
import pandas as pd
import matplotlib.pyplot as plt

# NetCDF4-Python can read a remote OPeNDAP dataset or a local NetCDF file:
url='http://thredds.ucar.edu/thredds/dodsC/grib/NCEP/WW3/Global/Best'
nc = netCDF4.Dataset(url)
nc.variables.keys()

lat = nc.variables['lat'][:]
lon = nc.variables['lon'][:]
time_var = nc.variables['time']
dtime = netCDF4.num2date(time_var[:],time_var.units)

# determine what longitude convention is being used [-180,180], [0,360]
print lon.min(),lon.max()

# specify some location to extract time series
lati = 41.4; loni = -67.8 +360.0  # Georges Bank

# find closest index to specified value
def near(array,value):
    idx=(abs(array-value)).argmin()
    return idx

# Find nearest point to desired location (could also interpolate, but more work)
ix = near(lon, loni)
iy = near(lat, lati)

# Extract desired times.      
# 1. Select -+some days around the current time:
start = dt.datetime.utcnow()- dt.timedelta(days=3)
stop = dt.datetime.utcnow()+ dt.timedelta(days=3)
#       OR
# 2. Specify the exact time period you want:
#start = dt.datetime(2013,6,2,0,0,0)
#stop = dt.datetime(2013,6,3,0,0,0)

istart = netCDF4.date2index(start,time_var,select='nearest')
istop = netCDF4.date2index(stop,time_var,select='nearest')
print istart,istop

# Get all time records of variable [vname] at indices [iy,ix]
vname = 'Significant_height_of_wind_waves_surface'
#vname = 'surf_el'
var = nc.variables[vname]
hs = var[istart:istop,iy,ix]
tim = dtime[istart:istop]

# Create Pandas time series object
ts = pd.Series(hs,index=tim,name=vname)

# Use Pandas time series plot method
ts.plot(figsize(12,4),
   title='Location: Lon=%.2f, Lat=%.2f' % ( lon[ix], lat[iy]),legend=True)
plt.ylabel(var.units);

#write to a CSV file
ts.to_csv('time_series_from_netcdf.csv')
这两种方法都会创建此绘图,以验证您是否已获得所需的数据:

并将所需的CSV文件
time\u series\u从\u netcdf.CSV
写入磁盘


你也可以

属性错误的问题是因为
content
需要是一个列表,而您使用
lat
初始化它,它只是一个数字。你需要把它填入一个列表

关于3D变量,
lats=nc。变量['latitude'][:]
足以读取所有数据

更新:一起迭代lon/lat

以下是列表和迭代的mod代码:

# the csv file is closed when you leave the block
with open('output.csv', 'wb') as csvFile:
    outputwriter = csv.writer(csvFile, delimiter=',')
    for time_index, time in enumerate(times): # pull the dates out for the header
        t = num2date(time, units = units, calendar='365_day')
        header.append(t)
    outputwriter.writerow(header)

    for latlon_index, (lat,lon) in enumerate(zip(lats, lons)):
        content = [lat, lon] # Put lat and lon into list
        print latlon_index
        for time_index, time in enumerate(times): # for a date
            # pull out the data 
            data = sfc[time_index,lat_index,lon_index]
            content.append(data)
            outputwriter.writerow(content)``
我实际上还没有试过运行它,所以可能还存在其他问题。

非常有用!请注意,还必须导入datetime,提取时间时,必须使用以下代码:

import datetime
import netCDF4
import pandas as pd
import matplotlib.pyplot as plt

...

# 2. Specify the exact time period you want:
start = datetime.datetime(2005,1,1,0,0,0)
stop = datetime.datetime(2010,12,31,0,0,0)

然后,我遍历了数据集所需的所有区域。

为什么需要它作为CSV?由于Dataset将数据存储为Numpy数组,您最好使用内置的
numpy.savetxt
函数来写入文档中的文本文件。是否要在lat/lon数组中搜索给定的点,并找到对应的Min_SFC值?DopplerShift我想在lat/lon中迭代一个日期,然后像示例表一样写入Min_SFC在邮局提供。我不想搜索或查找特定的lat/lon或日期我的主要问题是确保写入文件的所有数据都是针对同一记录。我查看了numpy.savetext,发现了一个插入逗号以创建CSV文件的示例。我不确定如何根据我在post中提供的示例(表)格式化输出文件中的纬度、经度、日期和sfc数据。
numpy.savetxt
具有
标题和
分隔符。前者应使您能够指定所需的顶行,后者应使您能够根据需要放入选项卡以生成所需的列。访问Numpy阵列子集(即所需的lat和lon范围)的最佳方法是通过Numpy。哦,我现在明白了,也许我没有仔细阅读这个问题。我认为在特定的位置需要一个时间序列。也许这不是目的。我试图在不知道netcdf文件名和变量名以外的任何信息的情况下将数据写入CSV。当从日期字段中删除时间时,我得到了一个属性错误,知道为什么吗?我正在使用Anaconda Spyder作为我的IDE。AttributeError:'numpy.ndarray'对象没有属性'strftime'date_strings=[dates.strftime('%Y%m%d')表示日期中的日期]我已经安装了numpy模块并导入了所有库,从numpy import*在那里键入,您想要:[date.strftime('%Y%m%d')表示日期中的日期](您正在按“日期”顺序在每个“日期”上调用strftime).content=[lat]解决了错误。我发布的代码的逻辑是错误的,对于每个lat索引,代码都会迭代所有lon索引。在调用data=sfc[time\u index,lat\u index,lon\u index]时,不必确保lat和lon使用相同的索引。这是主要的
import datetime
import netCDF4
import pandas as pd
import matplotlib.pyplot as plt

...

# 2. Specify the exact time period you want:
start = datetime.datetime(2005,1,1,0,0,0)
stop = datetime.datetime(2010,12,31,0,0,0)