Skip to content

Commit 7f37790

Browse files
author
Jonathan Rocher
committed
Demo reading a netCDF file and overlaying its content over a worldmap (cylindrical projection).
1 parent 4e6fb72 commit 7f37790

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

netCDF/read_netCDF_basemap.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
"""
2+
Reading netCDF climate data and ploting it over the woldmap
3+
"""
4+
from os.path import join, dirname
5+
import numpy as np
6+
from netCDF4 import Dataset
7+
from matplotlib.pyplot import figure, imshow, show
8+
from mpl_toolkits.basemap import Basemap, shiftgrid
9+
10+
def print_content_info(filename):
11+
""" Load a netcdf filename and print out the metadata of the file.
12+
This gives you something kinda similar to ncdump.
13+
TODO: make it closer to ncdump
14+
"""
15+
print "Opening netCDF file %s" % filename
16+
ncfile = Dataset(filename, mode='r')
17+
print "File format:", ncfile.file_format
18+
print "Metadata :"
19+
for attr in ncfile.ncattrs():
20+
print " "*4, attr, ":", getattr(ncfile,attr)
21+
22+
print "Structure of the content:", ncfile.groups.keys()
23+
for child_grp in ncfile.groups.values():
24+
if child_grp.groups:
25+
print " "*8+"Content of %s is " % (child_grp, child_grp.groups)
26+
27+
print "Dimensions defined at the top level:"
28+
for dim,val in ncfile.dimensions.items():
29+
print " Dimension '%s' with length %s" % (dim, len(val))
30+
for child_grp in ncfile.groups.values():
31+
if child_grp.dimensions:
32+
for dim,val in ncfile.dimensions.items():
33+
print " "*8+"Dimension '%s' with length %s" % (dim, len(val))
34+
35+
print "Variables in root group:"
36+
for var_name,val in ncfile.variables.items():
37+
print " "*4+"Variable '%s' of shape %s" % (var_name, val.shape)
38+
if val.ncattrs():
39+
print " "*4+"metadata: "
40+
for attr in val.ncattrs():
41+
print " "*8, attr, ":", getattr(val,attr)
42+
43+
if ncfile.groups.values():
44+
print "Variables in other groups:"
45+
for child_grp in ncfile.groups.values():
46+
if child_grp.variables:
47+
print " "*8+"Content of %: %s" % (child_grp, child_grp.variables)
48+
49+
return ncfile
50+
51+
def extract_data(ncfile, sliced = False, lat_0=None, lon_0=None, spot = False):
52+
""" Extract a given variable and return a 2D array. Slice it to only select
53+
the northern hemisphere if requested. If spot is True, extract only the
54+
value located at (lat,lon)
55+
"""
56+
relevant_array = ncfile.variables["207.210"]
57+
lat = ncfile.variables["latitude"]
58+
longit = ncfile.variables["longitude"]
59+
# The lat variables must be converted to a numpy array for the mask
60+
# to be an array instead of a boolean
61+
lat = np.array(lat)
62+
longit = np.array(longit)
63+
64+
if sliced:
65+
slice_north_lat = (0 <= lat) & (lat <= 90)
66+
relevant_array = relevant_array[0, slice_north_lat, :]
67+
68+
if spot:
69+
if lat_0 is None or lon_0 is None:
70+
raise ValueError("Requested the value in 1 location but didn't "
71+
"provide a latitude and a longitude")
72+
mask_lat = lat == lat_0
73+
mask_long = longit == lon_0
74+
relevant_array = relevant_array[0, mask_lat, mask_long]
75+
76+
return np.squeeze(relevant_array)
77+
78+
def plot_2Ddata(data_array):
79+
""" Plot of a 2D array.
80+
"""
81+
figure()
82+
imshow(data_array, origin = 'upper')
83+
return
84+
85+
def plot_2Ddata_with_underlay(data_array, lons=None, lats=None):
86+
""" Plot of a 2D array on top of coast lines and country lines.
87+
"""
88+
figure()
89+
90+
# Create the basemap instance and draw the continents
91+
# Basemap kw args: llcrnrlon = lower left corner longitude, and so on
92+
m = Basemap(llcrnrlon=-180, llcrnrlat=-90, urcrnrlon=180, urcrnrlat=90, projection='mill')
93+
m.drawcoastlines(linewidth=1.25)
94+
m.drawcountries(linewidth=0.5)
95+
#m.fillcontinents(color='0.8')
96+
m.drawparallels(np.arange(-90,91,20),labels=[1,1,0,0])
97+
m.drawmeridians(np.arange(-180,180,60),labels=[0,0,0,1])
98+
99+
# Shift the data by 180 in longitude to center the map on longitude=0
100+
data_array, lon_out = shiftgrid(180, data_array, lons)
101+
102+
# Add the data, and place origin in upper left since the origin of the numpy
103+
# array corresponds tolat = 90 and long = 0
104+
m.imshow(data_array, origin = 'upper')
105+
106+
# More complex version that involves interpolation on a grid of points in
107+
# map coordinates.
108+
#nx = int((m.xmax-m.xmin)/500.)+1; ny = int((m.ymax-m.ymin)/500.)+1
109+
#dat_array = m.transform_scalar(data_array, lons,lats,nx,ny)
110+
#m.imshow(dat_array, origin = 'upper')
111+
112+
113+
#figure()
114+
#m = Basemap(projection='ortho',lon_0=-105,lat_0=40)
115+
#m.drawcoastlines(linewidth=1.25)
116+
#m.drawcountries(linewidth=0.5)
117+
#dat_transformed = m.transform_scalar(data_array,
118+
119+
return
120+
121+
if __name__ == "__main__":
122+
# 1. Provide a quick description of the content of the file
123+
script_location = dirname(__file__)
124+
ncfile = print_content_info(join(script_location, "climate.nc"))
125+
126+
# 2. Extract and plot the entire 2D array of data
127+
lat = ncfile.variables["latitude"][:]
128+
longit = ncfile.variables["longitude"][:]
129+
print "Latitude range:", lat[0], lat[-1]
130+
print "Longitude range:", longit[0], longit[-1]
131+
full_data_image = extract_data(ncfile)
132+
plot_2Ddata(full_data_image)
133+
134+
# 3. Extract and plot the data that is in the northern hemisphere only,
135+
# and print the data in Paris (lat = 48N, long = 2E)
136+
sliced_data_image = extract_data(ncfile, sliced = True)
137+
plot_2Ddata(sliced_data_image)
138+
139+
print "In Paris, the measured value is", extract_data(ncfile, lat_0=48,
140+
lon_0=2, spot = True)
141+
142+
# 4. Underlay the map of the world under the global image
143+
#lat.sort()
144+
plot_2Ddata_with_underlay(full_data_image, longit, lat)
145+
146+
show()

0 commit comments

Comments
 (0)