Python: Plotting a regular grid of data in a latitude longitude grid - python

I have a grid of data points with a value of latitude/longitude for each row/column. I want to plot this to give a nice looking map. How do I go about this? I have tried converting the latitude/longitude row/column 'titles' to cartesian but cant get this to work.
from netCDF4 import Dataset
from mpl_toolkits.basemap import Basemap, cm
import matplotlib.pyplot as plt
general_file = 'data\ir2_20160815_114117_232_l3b_v10.nc'
file_data = Dataset(general_file)
lat = file_data.variables['latitude']
lon = file_data.variables['longitude']
rad = file_data.variables['radiance']
latitudes = lat[:]
longitudes = lon[:]
radiances = rad[0]
x= longitudes
y=latitudes
z = radiances
plt.contourf(x, y, z,25,cmap='Greys')
plt.title(general_file)
plt.colorbar()
plt.show()
The data file was downloaded from https://darts.isas.jaxa.jp/pub/pds3/extras/vco_ir2_l3_v1.0/vcoir2_7001/data/l3b/netcdf/r0024/

You could do this using my package ncplot (https://pypi.org/project/ncplot/).
import ncplot
ncplot.view('data\ir2_20160815_114117_232_l3b_v10.nc', "radiance")

Related

python matplotlib basemap show polygons in a map

I am trying to render a polygon using python matplot Basemap lib.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def render_polygon(lat, long):
map = Basemap(llcrnrlon=-10,llcrnrlat=35,urcrnrlon=35,urcrnrlat=60.,
resolution=None, projection='tmerc', lat_0 =
8.30, lon_0 = 3.46)
map.plot(lat, long, marker=None,color='m')
plt.show()
lat = [56.1304, 55.1304, 54.1304, 53.1304, 52.1304]
long = [106.3468, 107.3468, 105.3468, 104.3468, 103.3468]
render_polygon(lat, long)
When I run the program passing the latitude longitude I see an empty rectangle.
Can someone point out what am I doing incorrect?
You need to transform coordinates in the process.
Try changing
map.plot(lat, long, marker=None, color='m')
to
map.plot(*map(long, lat), marker=None, color='m')
The code *map(long, lat) does the required coordinate transformation, and spreads the result to xs, ys in that place.
Edit 1
The original code have been edited to get appropriate data extent, proper projection parameters.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
def render_polygon(lat, long):
map = Basemap(llcrnrlon=103, llcrnrlat=50, urcrnrlon=107.5, urcrnrlat=60.,
resolution='c', projection='merc',
lat_0 = 50, lon_0 = 105)
map.plot(*map(long, lat), marker=None, color='m')
#map.drawcoastlines(linewidth=0.7)
plt.show()
lat = [56.1304, 55.1304, 54.1304, 53.1304, 52.1304]
long = [106.3468, 107.3468, 105.3468, 104.3468, 103.3468]
render_polygon(lat, long)
The output plot:

Avoid interpolation of data when plotting map using latitude and longitude instead of provided x-y coordinates

I have a 2-d numpy array with with some data, in x and y coordinates. With each x and y point is also associated a latitude and a longitude (also 2-d numpy arrays). There are some values in the oceans, but not over land.
When I plot the data in x and y coordinates, I get the following:
plt.imshow(data)
Then, I want to plot this data on a map using lon-lat coordinates. If I do so as following, I get some plotted data on land, since some interpolation is operated.
import cartopy.crs as ccrs
ax = plt.axes(projection=ccrs.Robinson())
plt.pcolor(lon, lat, data, transform=ccrs.PlateCarree())
ax.coastlines()
I obtain the same for any type of plot that I can use on a map (pcolormesh, contour, contourf).
How can this be avoided since no data would show on land, where values should be Nans?
Thank you!
The data is part of the CMIP6 project. It can be accessed through Pangeo by accessing ocean.pangeo.io and running the following code:
from matplotlib import pyplot as plt
import numpy as np
import pandas as pd
import xarray as xr
import zarr
import gcsfs
import intake
from dask.distributed import Client
from dask_kubernetes import KubeCluster
cluster = KubeCluster()
cluster.adapt(minimum=1, maximum=20, interval='2s', wait_count=10)
client = Client(cluster)
client
url = 'https://raw.githubusercontent.com/NCAR/intake-esm-datastore/master/catalogs/pangeo-cmip6.json'
col = intake.open_esm_datastore(url)
col_hist = col.search(variable_id='o2', table_id='Omon', experiment_id='historical')
dict_hist = col_hist.to_dataset_dict(zarr_kwargs={'consolidated': True})
import cartopy.crs as ccrs
import cartopy.feature as cfeature
models = list(dict_hist.keys())
model = models[5]
ds = dict_hist[model]
sub1 = ds.o2.sel(member_id=ds.member_id.values[0], time=ds.time.values[0])
sub2 = sub1.sel(lev=100, method='nearest')
ax = plt.axes(projection=ccrs.Robinson())
q = sub2.plot(ax=ax, transform=ccrs.PlateCarree(), x='lon', y='lat', vmin=0, vmax=0.4, cbar_kwargs={'shrink': 0.5})
ax.set_global(); ax.coastlines();
Edited to account for comments on data.
The issue with the filled areas is one of wrapping. What you see is data plotting from e.g. +179.8 (right side of plot) to -178.4 (left side of plot)--CartoPy is not correctly clipping, so you have long streaks of data plotting across the map. In areas with other data plotted, these streaks are covered. Where you have no data plotted (i.e. on land) the streaks show through.
One work-around is to adjust the origin of the projection, which can eliminate some of those lines. I've had some success with small adjustments (~1 degree), but the best would be to make it so that the left and right edges of the original domain of the data are the left and right edges of the plot. For this dataset the left edge is +73.5 longitude, so we want the origin to be that +180, which is -107.5 longitude:
import intake
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
url = ('https://raw.githubusercontent.com/NCAR/'
'intake-esm-datastore/master/catalogs/pangeo-cmip6.json')
col = intake.open_esm_datastore(url)
col_hist = col.search(variable_id='o2', table_id='Omon', experiment_id='historical')
dict_hist = col_hist.to_dataset_dict(zarr_kwargs={'consolidated': True})
models = list(dict_hist.keys())
model = models[5]
ds = dict_hist[model]
sub1 = ds.o2.sel(member_id=ds.member_id.values[0], time=ds.time.values[0])
sub2 = sub1.sel(lev=100, method='nearest')
ax = plt.axes(projection=ccrs.Robinson(central_longitude=-107.5))
q = sub2.plot(ax=ax, transform=ccrs.PlateCarree(), x='longitude', y='latitude',
vmin=0, vmax=0.4, cbar_kwargs={'shrink': 0.5})
ax.coastlines()
ax.set_global()
which gives me this image:
Ideally, CartoPy would handle this correctly, but right now there are lots of issues with this (like this one for example).

Plotting a masked Antarctica with a shapefile or geopandas

I'm trying to plot data around the Antarctica while masking the continent. While I'm using basemap and it has an option to easily mask continents using map.fillcontinents(), the continent considered by basemap includes the ice shelves, which I do not want to mask.
I tried using geopandas from a code I found on the Internet. This works, except the coastline produces an undesired line in what I assume is the beginning/end of the polygon for the Antarctica:
import numpy as np
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
import geopandas as gpd
import shapely
from descartes import PolygonPatch
lats = np.arange(-90,-59,1)
lons = np.arange(0,361,1)
X, Y = np.meshgrid(lons, lats)
data = np.random.rand(len(lats),len(lons))
world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))
fig=plt.figure(dpi=150)
ax = fig.add_subplot(111)
m = Basemap(projection='spstere',boundinglat=-60,lon_0=180,resolution='i',round=True)
xi, yi = m(X,Y)
cf = m.contourf(xi,yi,data)
patches = []
selection = world[world.name == 'Antarctica']
for poly in selection.geometry:
if poly.geom_type == 'Polygon':
mpoly = shapely.ops.transform(m, poly)
patches.append(PolygonPatch(mpoly))
elif poly.geom_type == 'MultiPolygon':
for subpoly in poly:
mpoly = shapely.ops.transform(m, poly)
patches.append(PolygonPatch(mpoly))
else:
print(poly, 'blah')
ax.add_collection(PatchCollection(patches, match_original=True,color='w',edgecolor='k'))
The same line appears when I try to use other shapefiles, such as the land one that is available to download for free from Natural Earth Data. So I edited this shapefile in QGIS to remove the borders of the Antarctica. The problem now is that I don't know how to mask everything that's inside the shapefile (and couldn't find how to do it either). I also tried combining the previous code with geopandas by setting the linewidth=0, and adding on top the shapefile I created. The problem is that they are not exactly the same:
Any suggestion on how to mask using a shapefile, or with geopandas but without the line?
Edit: Using Thomas Khün's previous answer with my edited shapefile produces a well masked Antarctica/continents, but the coastline goes outside the round edges of the map:
I uploaded here the edited shapefile I used, but it's the Natural Earth Data 50m land shapefile without the line.
Here an example of how to achieve what you want. I basically followed the Basemap example how to deal with shapefiles and added a bit of shapely magic to restrict the outlines to the map boundaries. Note that I first tried to extract the map outline from ax.patches, but that somehow didn't work, so I defined a circle which has a radius of boundinglat and transformed it using the Basemap coordinate transformation functionality.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
import shapely
from shapely.geometry import Polygon as sPolygon
boundinglat = -40
lats = np.arange(-90,boundinglat+1,1)
lons = np.arange(0,361,1)
X, Y = np.meshgrid(lons, lats)
data = np.random.rand(len(lats),len(lons))
fig, ax = plt.subplots(nrows=1, ncols=1, dpi=150)
m = Basemap(
ax = ax,
projection='spstere',boundinglat=boundinglat,lon_0=180,
resolution='i',round=True
)
xi, yi = m(X,Y)
cf = m.contourf(xi,yi,data)
#adjust the path to the shapefile here:
result = m.readshapefile(
'shapefiles/AntarcticaWGS84_contorno', 'antarctica',
zorder = 10, color = 'k', drawbounds = False)
#defining the outline of the map as shapely Polygon:
rim = [np.linspace(0,360,100),np.ones(100)*boundinglat,]
outline = sPolygon(np.asarray(m(rim[0],rim[1])).T)
#following Basemap tutorial for shapefiles
patches = []
for info, shape in zip(m.antarctica_info, m.antarctica):
#instead of a matplotlib Polygon, create first a shapely Polygon
poly = sPolygon(shape)
#check if the Polygon, or parts of it are inside the map:
if poly.intersects(outline):
#if yes, cut and insert
intersect = poly.intersection(outline)
verts = np.array(intersect.exterior.coords.xy)
patches.append(Polygon(verts.T, True))
ax.add_collection(PatchCollection(
patches, facecolor= 'w', edgecolor='k', linewidths=1., zorder=2
))
plt.show()
The result looks like this:
Hope this helps.
For anyone still trying to figure out a simple way to mask a grid from a shapefile, here is a gallery example from the python package Antarctic-Plots which makes this simple.
from antarctic_plots import maps, fetch, utils
import pyogrio
# fetch a grid and shapefile
grid = fetch.bedmachine(layer='surface')
shape = fetch.groundingline()
# subset the grounding line from the coastline
gdf = pyogrio.read_dataframe(shape)
groundingline = gdf[gdf.Id_text == "Grounded ice or land"]
# plot the grid
fig = maps.plot_grd(grid)
# plot the shapefile
fig.plot(groundingline, pen='1p,red')
fig.show()
# mask the inside region
masked_inside = utils.mask_from_shp(
shapefile=groundingline, xr_grid=grid, masked=True)
masked_inside.plot()
# mask the outside region
masked_outside = utils.mask_from_shp(
shapefile=groundingline, xr_grid=grid, masked=True, invert=False)
masked_outside.plot()

Python: Basemap precipitation data not showing up

I am using python 3.6 to plot precipitation data from CMIP5, the file I have downloaded is a netCDF4 file. I have used this code on another similar file and it worked out fine so I am not sure what the problem is. I am not receiving any error message with this code, it just displays a world map that is all one color when it should be a variety of colors. The variables found in this file are time, time_bnds, lat, lat_bnds, lon, lon_bnds, and prc. prc is the precipitation variable and the one I an interested in plotting. Any ideas would be helpful, Thank you!
Here is my code
from mpl_toolkits.basemap import Basemap, cm
from netCDF4 import Dataset as NetCDFFile
import matplotlib.pyplot as plt
nc = NetCDFFile('filename.nc','r')
p = nc.variables['prc']
data = p[:,:,0]
fig = plt.figure(figsize=(8,8))
ax = fig.add_axes([0.1,0.1,0.8,0.8])
m = Basemap(projection='cyl',lon_0=180,lat_0=0,resolution='l')
m.drawcoastlines()
m.drawstates()
m.drawcountries()
ny = data.shape[0]; nx = data.shape[1]
lons, lats = m.makegrid(nx,ny)
x,y = m(lons, lats) # compute map proj coordinates.
cs=plt.contourf(x,-y,data,range(0,1000,10),cmap=cm.s3pcpn,latlon=True)
cbar = m.colorbar(cs,location='bottom',pad="5%")
cbar.set_label('mm')
plt.show()

Plotting NOAA data with Basemap

I'm very new to Python but have been learning lots over the last few months. I'm trying to plot NOAA swell height data from a grib2 file located here: ftp://ftpprd.ncep.noaa.gov/pub/data/nccf/com/wave/prod/wave.20140122/nww3.t06z.grib.grib2
I use Basemap and a tutorial that I found on a Basemap forum.
A minimum working example is below, but I'm getting some strange white boxes around the coastline.
import Nio
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
import numpy as np
f = Nio.open_file('nww3.t12z.grib(2).grib2')
lons = f.variables['lon_0'][:]
lats = f.variables['lat_0'][::-1] # flip latitudes so data goes S-->N
times = f.variables['forecast_time0'][:]
ntime = 5
data = f.variables['HTSGW_P0_L1_GLL0'][ntime,::-1]
fig = plt.figure(figsize=(16,16))
m = Basemap(llcrnrlon=-35.,llcrnrlat=42.,urcrnrlon=5.,urcrnrlat=65.,
projection='lcc',lat_1=10.,lat_2=15.,lon_0=10.,
resolution ='h',area_thresh=1000.)
x, y = m(*np.meshgrid(lons, lats))
m.fillcontinents(color='#477519')
m.drawcoastlines(linewidth=0.5, color='k', antialiased=1, ax=None, zorder=None )
m.contourf(x, y, data, np.arange(0,9.9,0.1))
plt.show()
This is the result (the top panel; I would like it to look like the bottom panel): http://oi43.tinypic.com/s2s3m0.jpg
Sorry I don't have enough points to post images.
Thanks in advance,
Al

Categories

Resources