Contour data with cartopy - python

I am trying to plot some bathymetry data using cartopy. I slice out a section of the data and plot it over a Mercator projection. It produces a map that looks ok but I get the following error,
IllegalArgumentException: Invalid number of points in LinearRing found 3 - must be 0 or >= 4
Shell is not a LinearRing
Should I be worried about this? My code is below,
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['contour.negative_linestyle'] = 'solid'
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.feature as cfeature
from netCDF4 import Dataset
# load data and slice out region of interest
_file = 'GEBCO_2014_2D.nc'
gebco = Dataset(_file, mode='r')
g_lons = gebco.variables['lon'][:]
g_lon_inds = np.where((g_lons>=-30) & (g_lons<=10))[0]
g_lons = g_lons[g_lon_inds]
g_lats = gebco.variables['lat'][:]
g_lat_inds = np.where((g_lats>=40) & (g_lats<=65))[0]
g_lats = g_lats[g_lat_inds]
d = gebco.variables['elevation'][g_lat_inds, g_lon_inds]
gebco.close()
# plot data
projection=ccrs.Mercator()
extent = [-30, 10, 40, 65]
fig = plt.figure(figsize=(13.3, 10))
ax = fig.add_subplot(111, projection=projection)
lon_labels = np.arange(-30, 20, 10)
lat_labels = np.arange(40, 75, 10)
gl = ax.gridlines(draw_labels=True, xlocs=lon_labels, ylocs=lat_labels)
gl.xlabels_top = gl.ylabels_right = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
ax.set_extent(extent, crs=ccrs.PlateCarree())
coastline_10m = cfeature.NaturalEarthFeature('physical', 'coastline', '10m',
edgecolor='k', alpha=0.6,
facecolor=cfeature.COLORS['land'])
ax.add_feature(coastline_10m)
CS = plt.contour(g_lons, g_lats, d, [-1000,-150],
colors='k', alpha=0.4, linewidth=0.5, zorder=1,
transform=ccrs.PlateCarree())
plt.clabel(CS, inline=True, fontsize=10, fmt='%i')

Related

How to filter data while drawing?

I have a dataframe which I drawed as you can see the figure and codes below;
import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
df = pd.read_excel('nötronn.xlsx')
fig, ax = plt.subplots(figsize=(20,40))
ax1 = plt.subplot2grid((1,5), (0,0), rowspan=1, colspan = 1)
ax1.plot(df["N/F*10"], df['Depth'], color = "green", linewidth = 0.5)
ax1.set_xlabel("Porosity")
ax1.xaxis.label.set_color("green")
ax1.set_xlim(10, 50)
ax1.set_ylabel("Depth (m)")
ax1.tick_params(axis='x', colors="green")
ax1.spines["top"].set_edgecolor("green")
ax1.title.set_color('green')
ax1.set_xticks([10, 20, 30, 40, 50])
I want to filter data so that I can realize the differences better. I tried these:
z = np.polyfit(df["N/F*10"], df['Depth'], 2)
p = np.poly1d(z)
plt.plot(df["N/F*10"], p(df["N/F*10"]))
But it gives :LinAlgError: SVD did not converge in Linear Least Squares
How can I solve it? Thanks.
Output expectation:
This works!
import pandas as pd
from matplotlib import pyplot as plt
import numpy as np
from statsmodels.nonparametric.smoothers_lowess import lowess
data = pd.read_excel('nötronn.xlsx')
sub_data = data[data['Depth'] > 21.5]
result = lowess(sub_data['Eksi'], sub_data['Depth'].values)
x_smooth = result[:,0]
y_smooth = result[:,1]
tot_result = lowess(data['Eksi'], data['Depth'].values, frac=0.01)
x_tot_smooth = tot_result[:,0]
y_tot_smooth = tot_result[:,1]
fig, ax = plt.subplots(figsize=(20, 8))
##ax.plot(data.depth.values, data['N/F*10'], label="raw")
ax.plot(x_tot_smooth, y_tot_smooth, label="lowess 1%", linewidth=3, color="g")
ax.plot(data['GR-V121B-ETi'])
ax.plot(data['Caliper'], linestyle = 'dashed')

Spatial interpolation of discrete points onto x/y coordinate mesh grid in Python

I'm still very new to programming and trying to create a contour plot of alkalinity across Hawaii using Cartopy. I will need to interpolate the point values called MODIFIED_TA against an x-y mesh grid but have not been able to figure out how to do this. The code I'm using is:
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import cartopy.crs as ccrs
import cartopy.mpl.ticker as cticker
import statistics
from scipy.interpolate import UnivariateSpline
import numpy as np
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import warnings
warnings.filterwarnings("ignore") # ignoring the warning prompts.
%matplotlib inline
fig = plt.figure(figsize=(15,15))
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree(central_longitude=-170))
landgreen = cfeature.NaturalEarthFeature('physical', 'land', '110m',
edgecolor='face', facecolor='green')
oceanaqua = cfeature.NaturalEarthFeature('physical', 'ocean', '110m',
edgecolor='face', facecolor='aqua')
ax.set_extent([-151.5, -162, 18, 24], ccrs.PlateCarree())
ax.set_title('TOTAL ALKALINITY')
ax.add_feature(landgreen)
ax.add_feature(cfeature.OCEAN, color = 'k')
ax.gridlines(draw_labels=True)
lon_formatter = cticker.LongitudeFormatter()
lat_formatter = cticker.LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
ax.grid(linewidth=2, color='black', alpha=0.5, linestyle='--')
lons = all_data.LONGITUDE[:]
lats = all_data.LATITUDE[:]
alk = all_data.MODIFIED_TA[:]
x1,y1 = np.meshgrid(lons,lats)
z1,z2 = np.meshgrid(all_data.MODIFIED_TA,all_data.MODIFIED_TA)
plt.tricontourf(lons,lats,alk, transform=ccrs.PlateCarree(), cmap=cm.gist_rainbow)
plt.colorbar(shrink=0.5)
plt.title('$A_{T}$ VALUES', color = 'k', fontname='Times New Roman',size = 23)
plt.plot()
The result is nothing like what I was hoping for and again, I'm not sure how to interpolate this value so that it comes out as a smooth gradient across the x/y coordinate grid. Any help would be greatly appreciated!
See output here
It's hard to tell for sure without being able to see your data. I tried to create a MRE and it worked. I would start by seeing if this works.
import cartopy.feature as cfeature
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.mpl.ticker as cticker
import numpy as np
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, projection=ccrs.PlateCarree(central_longitude=-170))
ax.set_extent([-151.5, -162, 18, 24], ccrs.PlateCarree())
ax.add_feature(cfeature.OCEAN)
ax.gridlines(draw_labels=True)
lon_formatter = cticker.LongitudeFormatter()
lat_formatter = cticker.LatitudeFormatter()
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)
ax.grid(linewidth=2, color='black', alpha=0.5, linestyle='--')
lons = np.random.random(80) * 7 - 160
lats = np.random.random(80) * 4 + 19
alk = np.cos(lons * 10 * np.pi / 180) * np.sin(lats * 20 / 180)
plt.plot(lons, lats, 'k.', transform = ccrs.PlateCarree())
plt.tricontourf(lons,lats,alk, transform=ccrs.PlateCarree(), alpha = 0.5)
plt.colorbar(shrink=0.5)
plt.title('$A_{T}$ VALUES', color = 'k', fontname='Times New Roman',size = 23)
If it does work, then what I'd look at would include:
What are the dimensions of all_data.LONGITUDE, all_data.LATITUDE, all_data.MOTIFIED_TA?
Are there duplicate values?
Does it work when you plot it outside of a projection?
If my example does not work, then it suggests there is something about your install, in which case update it if you can. If the problem still persists, perhaps there is a bug cartopy that needs reporting or a conflict with other packages.
Sorry, I cannot help further.

Overlay/Fill country boundaries with image in

Is there a way to fill a country with an image similar to R solution using custom library here:
I have a solution where the face colour is filled for instance the below where Italy is blue. However, I would like to add the Italian flag. Is there a way in Python (I have not found much after searching) or is something like QGIS needed:
#create a map where I can load images in to fill the countries
import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
flag = "italy.png" #this is a locally saved png.
plt.figure(figsize=(15, 15)) #size of plot
ax = plt.axes(projection=cartopy.crs.TransverseMercator(25))
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', alpha=1)
ax.coastlines(resolution='110m') #simplifies the border lines
ax.add_feature(cartopy.feature.OCEAN, facecolor="#40e0d0") #colour of ocean
# ax.gridlines() #adds global grid lines
ax.set_extent ((-7.5, 50, 34, 69), cartopy.crs.PlateCarree()) #makes it european
shpfilename = shpreader.natural_earth(resolution='110m',
category='cultural',
name='admin_0_countries')
for country in shpreader.Reader(shpfilename).records():
if country.attributes['NAME_LONG'] == "Italy":
ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor="blue",
#no attribute like this img= "fd",
label=country.attributes['NAME_LONG'])
plt.show()
Any help, much appreciated!
Here is a demo code that does what you need. As a matter of fact, cartopy logo uses this technique to create.
import cartopy
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import matplotlib.patches as mpatches
import numpy as np
imdat1 = plt.imread('flag-of-italy.jpg', format='jpg') # use your flag
plt.figure(figsize=(8, 8))
ax = plt.axes(projection=cartopy.crs.TransverseMercator(25))
ax.add_feature(cartopy.feature.BORDERS, linestyle='-', alpha=1)
ax.coastlines(resolution='110m')
ax.add_feature(cartopy.feature.OCEAN, facecolor="#40e0d0")
# ax.gridlines() #adds global grid lines
ax.set_extent ((-7.5, 50, 24, 69), cartopy.crs.PlateCarree())
shpfilename = shpreader.natural_earth(resolution='110m',
category='cultural',
name='admin_0_countries')
italy_ctry = None #use this to grab italy's
for country in shpreader.Reader(shpfilename).records():
if country.attributes['NAME_LONG'] == "Italy":
italy_ctry = country
ax.add_geometries(country.geometry, ccrs.PlateCarree(),
facecolor="none",
alpha=0.7,
zorder=2,
label=country.attributes['NAME_LONG'])
# create mpatch from `italy` geometry
cg = italy_ctry.geometry
cg2 = cg.simplify(0.02)
if cg2.geometryType()=='MultiPolygon':
# if == `Polygon`, dont need to loop
for ea in cg2.geoms:
cg2xy = ea.exterior.xy # tuple of (x,y)
xys = []
for ea in zip(cg2xy[0], cg2xy[1]):
#print(ea[0],ea[1])
xys.append([ea[0],ea[1]])
# add a patch
poly = mpatches.Polygon(xys, closed=True, ec='r', \
lw=2, fc='yellow', \
transform=ccrs.PlateCarree(), \
alpha=0.5, zorder=30)
plate_carree_transform = ccrs.PlateCarree()._as_mpl_transform(ax)
xtent1 = (6.519950, 17.122259, 35.783370, 47.962952)
imdat2 = ax.imshow(imdat1, origin='upper', extent=xtent1, \
transform=ccrs.PlateCarree(), \
zorder=15, alpha=.9)
##imdat2 = ax.stock_img() #for testing
imdat2.set_clip_path(mpatches.Path(xys), transform=plate_carree_transform)
pass
plt.show()
The sample plot (varies with the flag in use):

Python Basemap Heatmap

I am trying to copy the method that was done on this page: https://makersportal.com/blog/2018/7/20/geographic-mapping-from-a-csv-file-using-python-and-basemap under "Mapping Interesting Data" to have a color bar associated with my data.
Right now I just get a plain map of South America, which is what I want as my background but there is no data included.
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
m = Basemap(projection='mill',
llcrnrlat = -30, #bottom
llcrnrlon = -120, #left
urcrnrlat = 20, #top
urcrnrlon = -50, #right
resolution='c')
m.drawcoastlines()
m.drawcountries()
# format colors for elevation range
SST_min = np.min(df5.DaasgardSST)
SST_max = np.max(df5.DaasgardSST)
cmap = plt.get_cmap('gist_earth')
normalize = matplotlib.colors.Normalize(vmin=SST_min, vmax=SST_max)
# plot SST with different colors
for i in range(0,len(df5.DaasgardSST)):
x,y = m(lon,lat)
color_interp = np.interp(df5,[SST_min,SST_max],[0,30])
plt.plot(x,y,marker='o',markersize=6,color=cmap(int(color_interp)))
# format the colorbar
cax, _ = matplotlib.colorbar.make_axes(ax)
cbar = matplotlib.colorbar.ColorbarBase(cax, cmap=cmap,norm=normalize,label='Elevation')
plt.title('Title')
plt.show()

Value Error; Printing out Blank Map

I am trying to grid plots on a map, but the grid is not showing up and I am getting a ValueError.
It says ValueError: not enough values to unpack (expected 2, got 1)
import numpy as np
import matplotlib.pyplot as plt
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
import cartopy.crs as ccrs
avglonlist=[-63.414436532479854, -63.41382404937334, -63.41320293629234, -63.4126322428388, -63.412060546875, -63.41134304470493]
avglatlist=[44.5523500343606, 44.55130764100617, 44.550250391568596, 44.54927937825529, 44.54830612909229, 44.5470865885415]
klist=['0.1243', '0.1304', '0.1321', '0.1281', '0.1358', '0.1105']
ax = plt.axes(projection=ccrs.PlateCarree())
#ax.set_extent((-65.0, -58, 40, 47.7), crs=crs_latlon)
ax.set_extent((-64.0, -61, 42.5, 45.0), crs=ccrs.PlateCarree())
#Add coastlines and meridians/parallels (Cartopy-specific).
plt.gca().coastlines('10m')
gl=ax.gridlines(crs=ccrs.PlateCarree(), draw_labels=True,
linewidth=1, color='gray', alpha=0.5, linestyle='-')
gl.xlabels_top = False
gl.ylabels_right = False
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
# Add a title, legend, and display.
ax.set_title("Mission #13: Attenuation Coeffiecient\n2012-06-12 17:48:00 til 2012-07-08 12:10:00")
plt.pcolormesh(avglonlist, avglatlist, klist, transform=ccrs.PlateCarree())
plt.clim(0.0,0.5)
plt.show()

Categories

Resources