Python: Plotting map in netCDF file using Basemap - python

I'm working with netCDF file for plotting the map. However, I'm new to it and there is very little progress and all I did is learning some tutorials. I have some difficulties when overlaying color onto the map. Here is my code (with the downloaded file):
from mpl_toolkits.basemap import Basemap, cm
from netCDF4 import Dataset
import numpy as np
import matplotlib.pyplot as plt
data = Dataset('filename','r')
lat = data.variables['lat'][:]
lon = data.variables['lon'][:]
time = data.variables['time'][:]
lwe_thickness = data.variables['lwe_thickness'][:]
data.close()
mp = Basemap(projection = 'mill',
llcrnrlon=lon.min(),
urcrnrlon=lon.max(),
llcrnrlat=lat.min(),
urcrnrlat=lat.max(),
resolution = 'c')
x, y = np.meshgrid(lon, lat)
x, y = mp(lon, lat)
mp.drawcoastlines()
mp.drawstates()
mp.drawcountries()
mp.drawmapboundary()
parallels = np.arange(0.,90,30.)
mp.drawparallels(parallels,labels=[1,0,0,0])
meridians = np.arange(-180.,180.,30.)
mp.drawmeridians(meridians,labels=[0,0,0,1])
cmesh = mp.pcolormesh(x,y,lwe_thickness,shading='flat',cmap=plt.cm.jet,latlon=True)
cbar = mp.colorbar(cmesh, location='right')
plt.show()

Related

How to plot the map correctly over the SST data in cartopy?

I am trying to plot L2 Sea Surface Temperature data and I want to plot it over the globe in a geostationary projection. I tried the following code:
import h5py
import sys
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
# First get data from HDF5 file with h5py:
fn = '/home/swadhin/project/insat/data/3RIMG_30MAR2018_0014_L2B_SST_V01R00.h5'
with h5py.File(fn) as f:
print(list(f.keys()))
image = 'SST'
img_arr = f[image][0,:,:]
# get _FillValue for data masking
img_arr_fill = f[image].attrs['_FillValue'][0]
# retrieve extent of plot from file attributes:
left_lon = f.attrs['left_longitude'][0]
right_lon = f.attrs['right_longitude'][0]
lower_lat = f.attrs['lower_latitude'][0]
upper_lat = f.attrs['upper_latitude'][0]
sat_long = f.attrs['Nominal_Central_Point_Coordinates(degrees)_Latitude_Longitude'][1]
sat_hght = f.attrs['Nominal_Altitude(km)'][0] * 1000.0 # (for meters)
print('Done reading HDF5 file')
## Use np.ma.masked_equal with integer values to
## mask '_FillValue' data in corners:
img_arr_m = np.ma.masked_equal(img_arr, img_arr_fill)
print(img_arr_fill)
print(np.max(img_arr_m))
print(np.min(img_arr_m))
#print(np.shape(img_arr_m))
# # Create Geostationary plot with cartopy and matplotlib
map_proj = ccrs.Geostationary(central_longitude=sat_long,satellite_height=sat_hght)
ax = plt.axes(projection=map_proj)
ax.coastlines(color='black',linewidth = 0.5)
#ax.add_feature(cfeature.BORDERS, edgecolor='white', linewidth=0.25)
#ax.add_feature(cfeature.STATES,edgecolor = 'red',linewidth = 0.5)
ax.gridlines(color='black', alpha=0.5, linestyle='--', linewidth=0.75, draw_labels=True)
#ax.add_geometries(ind_shapes,crs = map_proj, edgecolor = 'black', alpha = 0.5)
map_extend_geos = ax.get_extent(crs=map_proj)
plt.imshow(img_arr_m, interpolation='none',origin='upper',extent=map_extend_geos, cmap = 'jet')
plt.colorbar()
#plt.clim(-10,5)
plt.savefig('/home/swadhin/project/insat/data/l2_sst.png',format = 'png', dpi=1000)
The output I got is not very accurate. There are some SST values over some of the land areas which should not be the case.
I am adding the data here for people who wanna give it a try.
https://drive.google.com/file/d/126oW36JXua-zz3XMUcyZxwPj8UISDgUM/view?usp=sharing
I have checked your HDF5 file, and there are Longitude and Latitude variables in the file. So I think these WGS84 coordinates should be used.
First, the imshow method needs the image boundary information that cannot be obtained.
I also tried the pcolormesh method, but this method can not accept lon/lat array with NaN value.
In conclusion, the contourf seems to be the best choice, but this method still has the disadvantage that it is time-consuming to run.
import h5py
import sys
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.feature as cfeature
fn ='3RIMG_30MAR2018_0014_L2B_SST_V01R00.h5'
with h5py.File(fn) as f:
print(list(f.keys()))
image = 'SST'
img_arr = f[image][0,:,:]
lon = f['Longitude'][:]*0.01
lat = f['Latitude'][:]*0.01
# # get _FillValue for data masking
img_arr_fill = f[image].attrs['_FillValue'][0]
# # retrieve extent of plot from file attributes:
left_lon = f.attrs['left_longitude'][0]
right_lon = f.attrs['right_longitude'][0]
lower_lat = f.attrs['lower_latitude'][0]
upper_lat = f.attrs['upper_latitude'][0]
sat_long = f.attrs['Nominal_Central_Point_Coordinates(degrees)_Latitude_Longitude'][1]
sat_hght = f.attrs['Nominal_Altitude(km)'][0] * 1000.0 # (for meters)
print('Done reading HDF5 file')
## Use np.ma.masked_equal with integer values to
## mask '_FillValue' data in corners:
img_arr_m = np.ma.masked_equal(img_arr, img_arr_fill)
print(img_arr_fill)
print(np.max(img_arr_m))
print(np.min(img_arr_m))
lon_m = np.ma.masked_equal(lon, 327.67)
lat_m = np.ma.masked_equal(lat, 327.67)
# # Create Geostationary plot with cartopy and matplotlib
map_proj = ccrs.Geostationary(central_longitude=sat_long,satellite_height=sat_hght)
# or map_proj = ccrs.PlateCarree()
ax = plt.axes(projection=map_proj)
ax.set_global()
ax.coastlines(color='black',linewidth = 0.5)
ax.add_feature(cfeature.BORDERS, edgecolor='white', linewidth=0.25)
ax.add_feature(cfeature.STATES,edgecolor = 'red',linewidth = 0.5)
ax.gridlines(color='black', alpha=0.5, linestyle='--', linewidth=0.75, draw_labels=True)
cb = ax.contourf(lon_m,lat_m,img_arr_m, cmap = 'jet',transform = ccrs.PlateCarree())
plt.colorbar(cb)
plt.savefig('l2_sst1.png',format = 'png', dpi=300)
Here is the output figure.
or using a lon-lat projection.

Regridding and plotting netcdf file with irregular grid

I am trying to regrid my .nc data with irregular grid with the following code:
from mpl_toolkits.basemap import Basemap
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
import numpy as np
from scipy.interpolate import griddata
nc = NetCDFFile('test.nc')
lat = nc.variables['latitude'][:]
lon = nc.variables['longitude'][:]
time = nc.variables['time'][:]
ssi = nc.variables['solar_irradiation'][:]
XI = np.arange(46.025, 56.525, 0.05)
YI = np.arange(5.025, 15.525, 0.05)
lat_new, lon_new = np.meshgrid(XI, YI)
new_grid = griddata((lat, lon), ssi, (lat_new, lon_new), method='linear')
It works fine, there are NaN values at lat/lon boxes which are not in the original file.
Then I want to plot it using Basemap:
map = Basemap(projection='merc', llcrnrlon=-5., llcrnrlat=35., urcrnrlon=30., urcrnrlat=60.,
resolution='i')
map.drawcountries()
map.drawcoastlines()
x, y = map(XI, YI)
rad = map.contourf(x, y, new_grid)
cb = map.colorbar(rad, "bottom", size="10%", pad="10%")
I am receiving following error: IndexError: too many indices for array: array is 1-dimensional, but 2 were indexed. I know that this means, but I have no clue how to change to code so that it worked the same way. Thank you for every help!

Plot cotour graph on folium map

I've drawn a contour plot using matplolib and i want to overly this plot over folium map or is there any way to draw contour plot on map using folium
This is my code
import json
import numpy as np
from scipy.interpolate import griddata
from matplotlib import pyplot as plt
f = open('data.json', 'r')
data = json.load(f)
temp = data['temp']
lon = data['lon']
lat = data['lat']
x = np.linspace(min(lon), max(lon), 100)
y = np.linspace(min(lat), max(lat), 100)
X,Y = np.meshgrid(x, y)
Z = griddata((lon, lat), temp, (X, Y), method='cubic')
plt.contour(X,Y, Z)
plt.show()
My data file data.json, below is how my plot looks now i want to plot this over map
it's not clear your geometry is correct, have reversed lat & lon
straight forward with https://pypi.org/project/geojsoncontour/
import json
import numpy as np
from scipy.interpolate import griddata
from matplotlib import pyplot as plt
import geojsoncontour
import geopandas as gpd
f = open('data.json', 'r')
data = json.load(f)
temp = data['temp']
lon = data['lon']
lat = data['lat']
y = np.linspace(min(lon), max(lon), 100)
x = np.linspace(min(lat), max(lat), 100)
X,Y = np.meshgrid(x, y)
Z = griddata((lat, lon), temp, (X, Y), method='cubic')
contour = plt.contour(X,Y, Z)
gdf = gpd.GeoDataFrame.from_features(json.loads(geojsoncontour.contour_to_geojson(
contour=contour,
min_angle_deg=3.0,
ndigits=5,
stroke_width=1))).set_crs("EPSG:4326")
m = gdf.explore(color=gdf["stroke"])
plt.show()
m

Can you plot streamlines on Robinson projections?

I'm trying to plot streamlines on a global map with the Robinson projection, but basemap doesn't seem to like the projected co-ordinates. Of course, it works fine for a plain old cylindrical projection, which is regular in the x direction.
Here is an example:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
u = np.ones((21,21))
v = np.ones((21,21))
lats = np.arange(-90,91,9)
lons = np.arange(-180,181,18)
x,y = np.meshgrid(lons,lats)
# It works for Cylindrical
mp = Basemap(projection='cyl')
xx,yy = mp(x,y)
mp.streamplot(xx,yy,u,v)
mp.drawcoastlines()
plt.show()
# But not Robinson
mp = Basemap(projection='robin',lon_0=0)
xx, yy = mp(x, y)
mp.streamplot(xx,yy,u,v)
mp.drawcoastlines()
plt.show()
It complains about the x co-ordinates, raising:
ValueError: The rows of 'x' must be equal
So is it possible to plot streamlines on Robinson projections?
With the command xx,yy = mp(x,y) a coordinate transformation according to the particular projection is applied to your lon and lats. For most projections this will result in a distorsion of the gird point such that rows of x are no longer equal, hence the error: ValueError: The rows of 'x' must be equal. To fix this you need to re-grid your data, e.g. like this:
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib as plt
u = np.ones((21,21))
v = np.ones((21,21))
lats = np.arange(-90,91,9)
lons = np.arange(-180,181,18)
x,y = np.meshgrid(lons,lats)
mp = Basemap(projection='robin',lon_0=0)
xx, yy = mp(x, y)
# generate a grid that is equally spaced in a plot with the current pojection
lons, lats, xxnew, yynew = mp.makegrid(21,21, returnxy=True)
# project the data onto the new grid
unew = plt.mlab.griddata(xx.flatten(), yy.flatten(),u.flatten(), xxnew, yynew ,interp='linear')
vnew = plt.mlab.griddata(xx.flatten(), yy.flatten(),v.flatten(), xxnew, yynew ,interp='linear')
mp.streamplot(xxnew,yynew,unew,vnew)
mp.drawcoastlines()
plt.show()

Contour will not plot over Python basemap

I am trying to plot a contour and quiver plot over a basemap. When I plot, I get no errors, but only the basemap will show. The netcdf file only has one point in it for lat and long, so I had to create a range of coordinates. Any ideas why this is happening?
import netCDF4
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import pylab
from mpl_toolkits.basemap import Basemap
from matplotlib.patches import Polygon
ncfile = netCDF4.Dataset('30JUNE2012_0400UTC.cdf', 'r')
dbZ = ncfile.variables['MAXDBZF']
u = ncfile.variables['UNEW']
v = ncfile.variables['VNEW']
#print u
#print v
#print dbZ
data = dbZ[0,0]
data.shape
#print data.shape
z_index = 0 # z-level you want to plot (0-19)
U = u[0,z_index, :,:] #[time,z,x,y]
V = v[0,z_index, :,:]
lats = np.linspace(35.0, 41.0, data.shape[0])
lons = np.linspace(-81.0,-73.0, data.shape[1])
# create the map
map = Basemap(llcrnrlat=36,urcrnrlat=40,\
llcrnrlon=-80,urcrnrlon=-74,lat_ts=20,resolution='c')
# load the shapefile, use the name 'states'
map.readshapefile('st99_d00', name='states', drawbounds=True)
# collect the state names from the shapefile attributes so we can
# look up the shape obect for a state by it's name
state_names = []
for shape_dict in map.states_info:
state_names.append(shape_dict['NAME'])
ax = plt.gca() # get current axes instance
x,y = map(*np.meshgrid(lats,lons))
levels = np.arange(5,60,3)
c = map.contourf(x,y,data, levels, cmap='jet')
plt.colorbar()
q=plt.quiver(U,V,width=0.002, scale_units='xy',scale=10)
qk= plt.quiverkey (q,0.95, 1.02, 20, '20m/s', labelpos='N')
plt.show()

Categories

Resources