Cartopy - Plot 2d geodata as function of 2d longitude and latitude - matplotlib

I would like to plot from the following netcdf file (R90C_20P_MSG_201403250100.nc) the 2d array RFnet as function of teh 2d arrays LONGITUDE and LATITUDE.
Download of netcdf file:
https://gigamove.rwth-aachen.de/de/download/fa5c22f8009f2af3f2c59b5d92ceea7f
or here https://drive.google.com/file/d/17s2XtzS6P6rvT_ceJLnH_dN_9A1S8ViR/view?usp=sharing
I tried the following:
import xarray as xr
data = xr.open_dataset('R90C_20P_MSG_201403250100.nc', engine='netcdf4')
print(data)
which give as output:
<xarray.Dataset>
Dimensions: (image_y: 565, image_x: 1215)
Dimensions without coordinates: image_y, image_x
Data variables: (12/15)
LONGITUDE (image_y, image_x) float32 ...
LATITUDE (image_y, image_x) float32 ...
TAUCO (image_y, image_x) float32 ...
RFLW (image_y, image_x) float32 ...
RFSW (image_y, image_x) float32 ...
TAUCI (image_y, image_x) float32 ...
... ...
OLRCICO (image_y, image_x) float32 ...
RSRCICO (image_y, image_x) float32 ...
RFnet (image_y, image_x) float32 ...
ATD (image_y, image_x) float32 ...
FUEL (image_y, image_x) float32 ...
PC (image_y, image_x) float32 ...
I can extract e.g.:
LONGITUDE=data['LONGITUDE']
LATITUDE=data['LATITUDE']
RFnet=data['RFnet']
and access the corresponding data with
LONGITUDE.data
LATITUDE.data
RFnet.data
A simple plot would be:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8, 4))
ax = fig.add_subplot(111)
img=plt.imshow(RFnet.data, cmap='seismic', vmin=-10, vmax=10)
ax.set_aspect('equal')
cbar = fig.colorbar(img, location='bottom', shrink=0.6, pad=0.15, ax=ax)
cbar.set_label('RFnet')
plt.show()
How can I plot RFnet as function of LONGITUDE and LATITUDE?
LATITUDE AND LONGITUDE ARE 2d ARRAYS:

fig = plt.figure(figsize=(12, 12))
pc = ccrs.PlateCarree()
ax = fig.add_subplot(projection=pc, extent=(-55.530094, 55.530094, 33.582264, 66.823235))
ax.set_global()
ax.coastlines(resolution='50m', # alternative: '110m', '50m', '10m'
color='grey')
ax.gridlines(draw_labels=True)
x = LONGITUDE.data
y = LATITUDE.data
c = RFnet.data
norm=mcolors.Normalize(vmin=-10, vmax=10)
cmap = "seismic"
ax.set_extent(extents=(-20, 20, 32, 52)) # x0, x1, y0, y1 in degrees
im = ax.scatter(x, y, c=c, cmap=cmap, norm=norm, s=2)
cbar = fig.colorbar(im, location='bottom', shrink=1, pad=0.05, ax=ax)
cbar.set_label('RFnet')
plt.show()

Related

Change units of matplotlib subplot (RA hh:mm to degrees)

I am trying to plot an image with axes in RA and DEC. I cannot figure out how to change units from h:m:s to deg for my RA axis. I tried the following 2 methods and my output axes were the same (ticks: 5h 42m 15s, 00, 41m 45s, ...)
filename = get_pkg_data_filename('flame.fits')
hdu = fits.open(filename)[0]
wcs = WCS(hdu.header)
fig = plt.figure()
fig.add_subplot(111, projection=wcs)
plt.imshow(hdu.data, origin='lower', cmap=plt.cm.viridis)
plt.xlabel('RA')
plt.ylabel('Dec')
plt.show()
METHOD 2:
flame = fits.getdata('flame.fits')
hdr = fits.getheader('flame.fits')
wcs = WCS(hdr)
ax = plt.subplot(projection=wcs)
plt.imshow(flame, origin='lower')
plt.xlabel('RA')
plt.ylabel('Dec')
plt.show()
How do I change the X-axis (RA) to degrees?
Thanks!
P.S.:
This
ax = fig.gca()
ra = ax.coords[0]
dec = ax.coords[1]
ra.set_format_unit('ra')
dec.set_format_unit('dec')
result in AttributeError: 'AxesSubplot' object has no attribute 'coords'

How do I plot a contour from a table of values?

I have a table that has 2 features (x,y) - and a vector with the same length that contains their corresponding values (z).
I'm trying to use matplotlib to print this as a 2D plot but I am get an error:
TypeError: Input z must be at least a (2, 2) shaped array, but has shape (5797, 1)
Is there any way to solve this? (since I am trying to use 1d arrays instead of 2d arrays)
The relevant code:
x, y = train_features[:,0], train_features[:,1]
z = train_predictions.detach()
print(x.size())
print(y.size())
print(z.size())
plt.figure()
CS = plt.contour(x, y, z)
CS = plt.contourf(x, y, z)
plt.clabel(CS, fontsize=8, colors='black')
cbar = plt.colorbar(CS)
The prints that result from the prints commands:
torch.Size([5797])
torch.Size([5797])
torch.Size([5797, 1])
EDIT:
I tried to implement this with a second method:
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import numpy as np
npts = 200
ngridx = 100
ngridy = 200
x = train_features[:,0]
y = train_features[:,1]
z = train_predictions.detach().squeeze()
fig, ax1 = plt.subplots()
# -----------------------
# Interpolation on a grid
# -----------------------
# A contour plot of irregularly spaced data coordinates
# via interpolation on a grid.
# Create grid values first.
xi = np.linspace(1, 10, ngridx)
yi = np.linspace(1, 10, ngridy)
# Perform linear interpolation of the data (x,y)
# on a grid defined by (xi,yi)
triang = tri.Triangulation(x, y)
interpolator = tri.LinearTriInterpolator(triang, z)
Xi, Yi = np.meshgrid(xi, yi)
zi = interpolator(Xi, Yi)
ax1.contour(xi, yi, zi, levels=100, linewidths=0.5, colors='k')
cntr1 = ax1.contourf(xi, yi, zi, levels=14, cmap="RdBu_r")
fig.colorbar(cntr1, ax=ax1)
ax1.plot(x, y, 'ko', ms=3)
ax1.set_title('grid and contour (%d points, %d grid points)' %
(npts, ngridx * ngridy))
But the resulting image was the following:
even though z's values are:
tensor([-0.2434, -0.2155, -0.1900, ..., 64.7516, 65.2064, 65.6612])

Plotting unordered points as a contourf in matplotlib

I have a list of dictionaries containing unordered data points:
print(data)
[{'ID': 1, 'Longitude': 18.6081, 'Latitude': 50.0977, 'Cost': -1.0},
{'ID': 2, 'Longitude': 18.6091, 'Latitude': 50.197700000000005, 'Cost': 4},
{'ID': 3, 'Longitude': 18.6081, 'Latitude': 50.297700000000006,'Cost':4},....]
I want to plot the value of 'cost' function as countorf using matplotlib.
So far I've tested the following code:
lat = []
lon = []
cost = []
for dataPoint in data:
if dataPoint["Cost"] == -1:
continue
lon.append(dataPoint["Longitude"])
lat.append(dataPoint["Latitude"])
cost.append(dataPoint["Cost"])
xi = np.linspace(min(lon), max(lon))
yi = np.linspace(min(lat), max(lat))
zi = griddata(lon, lat, cost, xi, yi, interp='linear')
#make a plot
plt.contourf(xi, yi, zi, 100)
plt.colorbar()
plt.show()
Above code works but It interpolates the values between data points and all I want to do is plot all points from data array on a plane with a color coresponding to it's 'cost' value. How can I do that?
Is this what you mean?
In [41]: import matplotlib.pyplot as plt ; from scipy.interpolate import griddata
In [42]: import numpy as np
In [43]: N = 300
In [44]: x = np.random.rand(N) ; y = np.random.rand(N)
In [45]: z = np.sin(x*10)+np.cos(y*4)+0.05*np.random.rand(N)
In [46]: xi = yi = np.linspace(0,1)
In [47]: zi = griddata(x, y, z, xi, yi, interp='linear')
In [48]: plt.contour(xi, yi, zi, 10) ;
In [49]: plt.scatter(x, y, c=z) ;
In [50]: plt.colorbar() ;

colormap for 3d bar plot in matplotlib applied to every bar

Does anyone know how to implement easily colormaps to 3d bar plots in matplotlib?
Consider this example, how do I change each bar according to a colormap? For example, short bars should be mainly blue, while taller bars graduate their colors from blue towards the red...
In the physical sciences, it's common to want a so-called LEGO plot, which is I think what the original user is going for. Kevin G's answer is good and got me to the final result. Here's a more advanced histogram, for x-y scatter data, colored by height:
xAmplitudes = np.random.exponential(10,10000) #your data here
yAmplitudes = np.random.normal(50,10,10000) #your other data here - must be same array length
x = np.array(xAmplitudes) #turn x,y data into numpy arrays
y = np.array(yAmplitudes) #useful for regular matplotlib arrays
fig = plt.figure() #create a canvas, tell matplotlib it's 3d
ax = fig.add_subplot(111, projection='3d')
#make histogram stuff - set bins - I choose 20x20 because I have a lot of data
hist, xedges, yedges = np.histogram2d(x, y, bins=(20,20))
xpos, ypos = np.meshgrid(xedges[:-1]+xedges[1:], yedges[:-1]+yedges[1:])
xpos = xpos.flatten()/2.
ypos = ypos.flatten()/2.
zpos = np.zeros_like (xpos)
dx = xedges [1] - xedges [0]
dy = yedges [1] - yedges [0]
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap - you can change this!
max_height = np.max(dz) # get range of colorbars so we can normalize
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.title("X vs. Y Amplitudes for ____ Data")
plt.xlabel("My X data source")
plt.ylabel("My Y data source")
plt.savefig("Your_title_goes_here")
plt.show()
Note: results will vary depending on how many bins you choose and how much data you use. This code needs you to insert some data or generate a random linear array. Resulting plots are below, with two different perspectives:
So maybe not exactly what you're looking for (perhaps a good starting point for you), but using
Getting individual colors from a color map in matplotlib
can give varying solid colors for the bars:
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.cm as cm # import colormap stuff!
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
x, y = np.random.rand(2, 100) * 4
hist, xedges, yedges = np.histogram2d(x, y, bins=4, range=[[0, 4], [0, 4]])
# Construct arrays for the anchor positions of the 16 bars.
# Note: np.meshgrid gives arrays in (ny, nx) so we use 'F' to flatten xpos,
# ypos in column-major order. For numpy >= 1.7, we could instead call meshgrid
# with indexing='ij'.
xpos, ypos = np.meshgrid(xedges[:-1] + 0.25, yedges[:-1] + 0.25)
xpos = xpos.flatten('F')
ypos = ypos.flatten('F')
zpos = np.zeros_like(xpos)
# Construct arrays with the dimensions for the 16 bars.
dx = 0.5 * np.ones_like(zpos)
dy = dx.copy()
dz = hist.flatten()
cmap = cm.get_cmap('jet') # Get desired colormap
max_height = np.max(dz) # get range of colorbars
min_height = np.min(dz)
# scale each z to [0,1], and get their rgb values
rgba = [cmap((k-min_height)/max_height) for k in dz]
ax.bar3d(xpos, ypos, zpos, dx, dy, dz, color=rgba, zsort='average')
plt.show()
Personally, I find that ugly as sin! But it probably won't look too bad with a sequential colormap - https://matplotlib.org/examples/color/colormaps_reference.html

How can I plot function values on a sphere?

I have a Nx2 matrix of lat lon coordinate pairs, spatial_data, and I have an array of measurements at these coordinates.
I would like to plot this data on a globe, and I understand that Basemap can do this. I found this link which shows how to plot data if you have cartesian coordinates. Does there exist functionality to convert lat,lon to cartesian coordinates? Alternatively, is there a way to plot this data with only the lat,lon information?
You can use cartopy:
import numpy as np
import matplotlib.pyplot as plt
from cartopy import crs
# a grid for the longitudes and latitudes
lats = np.linspace(-90, 90, 50)
longs = np.linspace(-180, 180, 50)
lats, longs = np.meshgrid(lats, longs)
# some data
data = lats[1:] ** 2 + longs[1:] ** 2
fig = plt.figure()
# create a new axes with a cartopy.crs projection instance
ax = fig.add_subplot(1, 1, 1, projection=crs.Mollweide())
# plot the date
ax.pcolormesh(
longs, lats, data,
cmap='hot',
transform=crs.PlateCarree(), # this means that x, y are given as longitude and latitude in degrees
)
fig.tight_layout()
fig.savefig('cartopy.png', dpi=300)
Result: