Removing Edge colors in Cartopy heatmap - python
I am attempting to plot a heatmap showing the density of lightning using python's cartopy and matplotlib libraries.
I have roughly followed the code here Cartopy Heatmap over OpenStreetMap Background . However, my plot shown below contains solid lines around each transparent bin, which is my problem. The other plot is the same code with random numbers. An ideal solution would be to not display the lines at all, or for the lines to match the bin's face color with the correct transparency. I've done a fair amount of trial and error to remove them in addition to reading some matplotlib documentation. According to the 2d-histogram docs , I should be plotting a QuadMesh object. You should be able to set the linewidth to 0, or have the edgecolor set to none in the QuadMesh. In my code below, I tried doing that yet the lines still persist. I've also tried the pcolormesh as well with the same result.
Here is my code.
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import cartopy.io.shapereader as shpreader
import cartopy.feature as cfeature
import cartopy.io.img_tiles as cimgt
import numpy as np
import random
#xsize and ysize are integers and lons, lats are 1d numpy arrays of longitude and latitude.
def testDensity(xsize, ysize, lons, lats):
#Some code below follows example
#https://stackoverflow.com/questions/50611018/cartopy-heatmap-over-openstreetmap-background
request = cimgt.OSM()
fig, ax = plt.subplots(figsize=(xsize,ysize),subplot_kw=dict(projection=request.crs), dpi=200)
extent = [-126,-118,41,44]
ax.set_extent(extent)
ax.add_image(request,8)
xynps = ax.projection.transform_points(ccrs.Geodetic(), lons, lats)#
print(xynps, type(xynps))
#Create 2-d histogram
histogram = ax.hist2d( xynps[:,0] , xynps[:,1] ,cmap='jet', bins=100, zorder=1,alpha=0.5,edgecolors="none",linewidth=0 )
print(histogram[3], dir(histogram[3]) )
histogram[3].set_linewidth(0.0)
histogram[3].set_edgecolor("none")
#histogram:(frequency, xedges, yedges, image QuadMesh)
#ax.pcolormesh(histogram[1], histogram[2], histogram[0], cmap = 'jet', alpha=0.5,edgecolors="none")
cbar = plt.colorbar(mappable=histogram[3], ax=ax , shrink=0.5, format='%.1f1' )
cbar.solids.set_rasterized("True")#Removes lines from colorbar
cbar.solids.set_edgecolor("face")
plt.savefig("densityTest.png", bbox_inches="tight")
#Generate random dataset
for i in range(0,800):
lon = random.randrange(41,44) + random.random()
lat = random.randrange(-126,-118) + random.random()
lons.append(lon)
lats.append(lat)
lons = np.array(lons)
lats = np.array(lats)
testDensity(9,34, lons, lats)
I can't reproduce the problematic results you showed us because of errors in your code. But once I correct the errors in the code and run. I get a good result as shown below.
The modified code:
def testDensity(xsize, ysize, lons, lats):
# Some code below follows example
# https://stackoverflow.com/questions/50611018/cartopy-heatmap-over-openstreetmap-background (That's my another answer)
request = cimgt.OSM()
fig, ax = plt.subplots(figsize=(xsize,ysize),subplot_kw=dict(projection=request.crs), dpi=200)
extent = [-126, -118, 41, 44]
ax.set_extent(extent)
ax.add_image(request, 8)
xynps = ax.projection.transform_points(ccrs.Geodetic(), lons, lats)
#Create 2-d histogram
# histogram = ax.hist2d(xynps[:,0],xynps[:,1],cmap='jet',bins=100,zorder=1,alpha=0.5,edgecolors="none",linewidth=0)
#This produces the same result, but shorter.
histogram = ax.hist2d( xynps[:,0], xynps[:,1], cmap='jet', bins=100, zorder=1, alpha=0.5)
# (Why use these code?)
#histogram[3].set_linewidth(0.0)
#histogram[3].set_edgecolor("none")
#ax.pcolormesh(histogram[1], histogram[2], histogram[0], cmap = 'jet', alpha=0.5,edgecolors="none")
# cbar = plt.colorbar(mappable=histogram[3], ax=ax , shrink=0.5, format='%.1f' )
# cbar.solids.set_rasterized("True")#Removes lines from colorbar
# cbar.solids.set_edgecolor("face")
# ... when this produces good result.
cbar = plt.colorbar(histogram[3], ax=ax, pad=0.03, aspect=28, shrink=0.26, format='%.1f') # h[3]: image
plt.savefig("densityTest.png", bbox_inches="tight")
plt.show()
#Generate random dataset
lons = []
lats = []
for i in range(0,800):
lat = random.randrange(41,44) + random.random()
lon = random.randrange(-126,-118) + random.random()
lons.append(lon)
lats.append(lat)
lons = np.array(lons)
lats = np.array(lats)
#testDensity(9,34, lons, lats)
testDensity(10,16, lons, lats)
The output plot:
Related
3D plot with multiple curves of data (frequency spectra) and color gradients to highlight the z-axis (magnitudes)
I'm trying to plot a series of frequency spectra in a 3D space using PolyCollection. My goal is to set "facecolors" as a gradient, i.e., the higher the magnitude, the lighter the color. Please see this image for reference (I am not looking for the fancy design, just the gradients). I tried to use the cmap argument of the PollyCollection, but I was unsuccessful. I came this far with the following code adapted from here: import matplotlib.pyplot as plt from matplotlib.collections import PolyCollection from mpl_toolkits.mplot3d import axes3d import numpy as np from scipy.ndimage import gaussian_filter1d def plot_poly(magnitudes): freq_data = np.arange(magnitudes.shape[0])[:,None]*np.ones(magnitudes.shape[1])[None,:] mag_data = magnitudes rad_data = np.linspace(1,magnitudes.shape[1],magnitudes.shape[1]) verts = [] for irad in range(len(rad_data)): xs = np.concatenate([[freq_data[0,irad]], freq_data[:,irad], [freq_data[-1,irad]]]) ys = np.concatenate([[0],mag_data[:,irad],[0]]) verts.append(list(zip(xs, ys))) poly = PolyCollection(verts, edgecolor='white', linewidths=0.5, cmap='Greys') poly.set_alpha(.7) fig = plt.figure(figsize=(24, 16)) ax = fig.add_subplot(111, projection='3d', proj_type = 'ortho') ax.add_collection3d(poly, zs=rad_data, zdir='y') ax.set_xlim3d(freq_data.min(), freq_data.max()) ax.set_xlabel('Frequency') ax.set_ylim3d(rad_data.min(), rad_data.max()) ax.set_ylabel('Measurement') ax.set_zlabel('Magnitude') # Remove gray panes and axis grid ax.xaxis.pane.fill = False ax.xaxis.pane.set_edgecolor('white') ax.yaxis.pane.fill = False ax.yaxis.pane.set_edgecolor('white') ax.zaxis.pane.fill = False ax.zaxis.pane.set_edgecolor('white') ax.view_init(50,-60) plt.show() sample_data = np.random.rand(2205, 4) sample_data = gaussian_filter1d(sample_data, sigma=10, axis=0) # Just to smoothe the curves plot_poly(sample_data) Besides the missing gradients I am happy with the output of the code above.
Axis labels for LambertConformal in cartopy at wrong location
I want to plot some data in a LambertConformal projection and add labels to the axes. See the example code below. However, now the x-labels show up twice, and both times in the middle of the plot, instead of at its bottom. When instead I set gl.xlabels_bottom = False and gl.xlabels_top = True, no x-labels are plotted at all. With the y-labels, I do not get this problem; they are just nicely plotted either along the left or right boundary of the plot. How can I get the x-labels at the right location (at the bottom of the figure)? import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs bounds_lon = [-45,-25] bounds_lat = [55,65] lon = np.arange(bounds_lon[0],bounds_lon[1]+0.1,0.1) lat = np.arange(bounds_lat[0],bounds_lat[1]+0.1,0.1) Lon, Lat = np.meshgrid(lon,lat) data = np.ones(np.shape(Lon)) data_crs = ccrs.PlateCarree() projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon),central_latitude=np.mean(bounds_lat),cutoff=bounds_lat[0]) plt.figure(figsize=(4,4)) ax = plt.axes(projection=projection) ax.coastlines() ax.contourf(Lon, Lat, data, transform=data_crs) gl = ax.gridlines(crs=ccrs.PlateCarree(), linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.xlabels_bottom = True
Manual repositioning of tick-labels are needed. To do that successfully, requires some other adjustments of the plot settings. Here is the code you can try. import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs bounds_lon = [-45,-25] bounds_lat = [55,65] # make-up data to plot on the map inc = 0.5 lon = np.arange(bounds_lon[0],bounds_lon[1]+inc, inc) lat = np.arange(bounds_lat[0],bounds_lat[1]+inc, inc) Lon, Lat = np.meshgrid(lon,lat) #data = np.ones(np.shape(Lon)) # original `boring` data data = np.sin(Lon)+np.cos(Lat) # better data to use instead data_crs = ccrs.PlateCarree() projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \ central_latitude=np.mean(bounds_lat), \ #cutoff=bounds_lat[0] ) # Note: `cutoff` causes horizontal cut at lower edge # init plot figure plt.figure(figsize=(15,9)) ax = plt.axes(projection=projection) ax.coastlines(lw=0.2) ax.contourf(Lon, Lat, data, transform=data_crs, alpha=0.5) # set gridlines specs gl = ax.gridlines(crs=ccrs.PlateCarree(), linewidth=2, color='gray', alpha=0.5, linestyle='--') gl.top_labels=True gl.bottom_labels=True gl.left_labels=True gl.right_labels=True plt.draw() #enable access to lables' positions xs_ys = ax.get_extent() #(x0,x1, y0,y1) #dx = xs_ys[1]-xs_ys[0] dy = xs_ys[3]-xs_ys[2] # The extent of `ax` must be adjusted # Extents' below and above are increased new_ext = [xs_ys[0], xs_ys[1], xs_ys[2]-dy/15., xs_ys[3]+dy/12.] ax.set_extent(new_ext, crs=projection) # find locations of the labels and reposition them as needed xs, ys = [], [] for ix,ea in enumerate(gl.label_artists): xy = ea[2].get_position() xs.append(xy[0]) ys.append(xy[1]) # Targeted labels to manipulate has "W" in them if "W" in ea[2].get_text(): x_y = ea[2].get_position() # to check which are above/below mid latitude of the plot # use 60 (valid only this special case) if x_y[1]<60: # labels at lower latitudes curpos = ea[2].get_position() newpos = (curpos[0], 54.7) # <- from inspection: 54.7 ea[2].set_position(newpos) else: curpos = ea[2].get_position() newpos = (curpos[0], 65.3) # <- from inspection: 65.3 ea[2].set_position(newpos) plt.show() Edit1 If you want to move all the lat/long labels to the outside edges, try this code. It is much more concise than the above. import numpy as np import matplotlib.pyplot as plt import cartopy.crs as ccrs bounds_lon = [-45,-25] bounds_lat = [55,65] inc = 0.5 lon = np.arange(bounds_lon[0],bounds_lon[1]+inc, inc) lat = np.arange(bounds_lat[0],bounds_lat[1]+inc, inc) Lon, Lat = np.meshgrid(lon,lat) #data = np.ones(np.shape(Lon)) # boring data data = np.sin(Lon)+np.cos(Lat) # more interesting data_crs = ccrs.PlateCarree() projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \ central_latitude=np.mean(bounds_lat), \ cutoff=bounds_lat[0] ) # init plot plt.figure(figsize=(15,9)) ax = plt.axes(projection=projection) ax.coastlines(lw=0.2) ax.contourf(Lon, Lat, data, transform=data_crs, alpha=0.3) gl = ax.gridlines(draw_labels=True, x_inline=False, y_inline=False, color='k', linestyle='dashed', linewidth=0.5) gl.top_labels=True gl.bottom_labels=True gl.left_labels=True gl.right_labels=True plt.show() If you want to get bottom edge as a straight line, you can achieve that by dropping the option cutoff=bounds_lat[0] from this line of code:- projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), \ central_latitude=np.mean(bounds_lat), \ cutoff=bounds_lat[0] ) so that it becomes projection = ccrs.LambertConformal(central_longitude=np.mean(bounds_lon), central_latitude=np.mean(bounds_lat)) and you will get the plot like this:-
Griddata and Contourf produce artifacts with increasing steps/levels
I am using SciPy Griddata to interpolate data in its Cartesian form and then plot these data using contourf with a polar projection. When the Cartesian interpolated data is plotted with contourf there are no artifacts. However, when the projection is polar, artifacts develop with increasing "levels". The artifacts are polygons or rays that form near regions of steep gradients. The code below plots the brightness of the sky with the moon. With graphlevels of "12" there isn't an issue. Artifacts develop with graphlevel of "25." My desired level is 80 or more - which shows terrible artifacts. The below is example real data from one night. These artifacts always occur. See images with Levels = 12 and Levels = 80 import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import griddata gridsize =150 graphlevels =12 plt.figure(figsize=(12,10)) ax = plt.subplot(111,projection='polar') x = [72.90,68.00,59.14,44.38,29.63,63.94,59.68,51.92,38.98,26.03,47.34,44.20,38.46,28.89,19.31,23.40,20.40,15.34,10.28,-0.18,-0.14,-0.09,-0.04,0.02,-25.39,-23.66,-20.57,-15.40,-10.23,-47.56,-44.34,-38.54,-28.89,-19.22,-64.01,-59.68,-51.89,-38.90,-25.90,-72.77,-67.84,-58.98,-44.21,-29.44,-72.75,-67.83,-58.96,-44.18,-29.41,-59.63,-51.82,-38.83,-25.84,-47.42,-44.20,-38.40,-28.76,-19.12,-23.40,-20.32,-15.19,-10.08,0.27,0.25,0.23,0.20,23.92,20.80,15.63,10.46,47.93,44.67,38.86,29.17,19.48,64.40,60.03,52.20,39.18,26.15,73.08,68.12,59.26,44.47,29.68,-4.81] y = [12.93,12.01,10.38,7.67,4.99,37.03,34.49,29.93,22.33,14.77,56.60,52.75,45.82,34.26,22.72,64.60,56.14,42.02,27.90,73.66,68.67,59.68,44.68,29.68,69.12,64.45,56.00,41.92,27.84,56.26,52.45,45.56,34.08,22.61,36.59,34.11,29.61,22.11,14.62,12.48,11.62,10.04,7.43,4.83,-13.33,-12.31,-10.78,-8.21,-5.58,-34.84,-30.36,-22.87,-15.36,-57.04,-53.20,-46.31,-34.83,-23.34,-65.20,-56.72,-42.62,-28.53,-69.33,-60.31,-45.31,-30.31,-65.09,-56.63,-42.55,-28.47,-56.81,-52.99,-46.13,-34.69,-23.23,-36.99,-34.53,-30.08,-22.66,-15.22,-12.73,-11.93,-10.44,-7.94,-5.40,-1.22,] skybrightness = [19.26,19.31,19.21,19.65,19.40,19.26,19.23,19.43,19.57,19.52,19.19,19.31,19.33,19.68,19.50,19.29,19.45,19.50,19.23,18.98,19.28,19.46,19.54,19.22,19.03,19.18,19.35,19.37,19.08,18.99,18.98,19.26,19.36,19.08,18.79,18.85,19.13,19.17,19.05,18.51,18.64,18.88,18.92,18.93,18.12,18.34,18.72,18.82,18.74,18.22,18.46,18.76,18.26,18.13,18.24,18.46,18.58,17.30,18.38,18.08,18.24,17.68,18.34,18.46,18.65,18.23,18.70,18.52,18.79,18.83,18.18,18.51,19.01,19.08,19.08,18.99,19.02,19.07,19.20,19.27,19.06,19.01,19.28,19.46,19.30,18.94] xgrid = np.linspace(min(x), max(x),gridsize) ygrid = np.linspace(min(y), max(y),gridsize) xgrid, ygrid = np.meshgrid(xgrid, ygrid, indexing='ij') nsb_grid = griddata((x,y),skybrightness,(xgrid, ygrid), method='linear') r = np.sqrt(xgrid**2 + ygrid**2) theta = np.arctan2(ygrid, xgrid) plt.rc('ytick', labelsize=16) ax.set_facecolor('#eeddcc') colors = plt.cm.get_cmap('RdYlBu') levels,steps = np.linspace(min(skybrightness), max(skybrightness)+0.3,graphlevels, retstep=True) ticks = np.linspace(min(skybrightness), max(skybrightness)+0.3,12) cax = ax.contourf(theta, r, nsb_grid, levels=levels, cmap=colors) cbar = plt.colorbar(cax, fraction=0.046, pad=0.04, ticks=ticks) cbar.set_label(r'mag/arcsec$^2$') ax.set_theta_zero_location('N') ax.set_theta_direction(-1) ax.set_rmax(75) ax.set_yticks(range(10, 80, 20)) ax.set_xticklabels([r'N', r'NE', r'E', r'SE', r'S', r'SW', r'W', r'NW']) ax.grid(alpha=0.3) plt.savefig('StackOverflowHELP.png')
I am going to leave my question and this answer on StackOverflow... because I did get an answer from the developers of Matploblib. The problem is Contourf . In its attempt to project data in polar dimensions there are overlaps and extensions of polygons at the cyclic boundaries that cause problems. The only way to avoid this is to add points at the boundary. To quote the developer: The workaround is a lot of effort and has to be tuned to each particular problem, so is a very long way from being ideal. We (Matplotlib) should do better in these situations. Inserting extra points into the triangulation isn't the right approach, we should instead correct the lines/polygons that traverse the discontinuity to provide a general solution. See https://github.com/matplotlib/matplotlib/issues/20060 for the full discussion The answer I settled on is to interpolate and render the result in Cartesian space. Then I format an empty polar plot with axes and labels to overlay on the top... and get on with my life! import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import griddata gridsize =150 graphlevels = 200 fig = plt.figure(figsize=(12,10)) ax = fig.add_subplot(111, aspect='equal') pax = fig.add_subplot(111,projection='polar') pax.set_facecolor('none') ax.set_axis_off() ax.set_xlim([-75,75]) ax.set_ylim([-75,75]) x = [72.90,68.00,59.14,44.38,29.63,63.94,59.68,51.92,38.98,26.03,47.34,44.20,38.46,28.89,19.31,23.40,20.40,15.34,10.28,-0.18,-0.14,-0.09,-0.04,0.02,-25.39,-23.66,-20.57,-15.40,-10.23,-47.56,-44.34,-38.54,-28.89,-19.22,-64.01,-59.68,-51.89,-38.90,-25.90,-72.77,-67.84,-58.98,-44.21,-29.44,-72.75,-67.83,-58.96,-44.18,-29.41,-59.63,-51.82,-38.83,-25.84,-47.42,-44.20,-38.40,-28.76,-19.12,-23.40,-20.32,-15.19,-10.08,0.27,0.25,0.23,0.20,23.92,20.80,15.63,10.46,47.93,44.67,38.86,29.17,19.48,64.40,60.03,52.20,39.18,26.15,73.08,68.12,59.26,44.47,29.68,-4.81] y = [12.93,12.01,10.38,7.67,4.99,37.03,34.49,29.93,22.33,14.77,56.60,52.75,45.82,34.26,22.72,64.60,56.14,42.02,27.90,73.66,68.67,59.68,44.68,29.68,69.12,64.45,56.00,41.92,27.84,56.26,52.45,45.56,34.08,22.61,36.59,34.11,29.61,22.11,14.62,12.48,11.62,10.04,7.43,4.83,-13.33,-12.31,-10.78,-8.21,-5.58,-34.84,-30.36,-22.87,-15.36,-57.04,-53.20,-46.31,-34.83,-23.34,-65.20,-56.72,-42.62,-28.53,-69.33,-60.31,-45.31,-30.31,-65.09,-56.63,-42.55,-28.47,-56.81,-52.99,-46.13,-34.69,-23.23,-36.99,-34.53,-30.08,-22.66,-15.22,-12.73,-11.93,-10.44,-7.94,-5.40,-1.22,] skybrightness = [19.26,19.31,19.21,19.65,19.40,19.26,19.23,19.43,19.57,19.52,19.19,19.31,19.33,19.68,19.50,19.29,19.45,19.50,19.23,18.98,19.28,19.46,19.54,19.22,19.03,19.18,19.35,19.37,19.08,18.99,18.98,19.26,19.36,19.08,18.79,18.85,19.13,19.17,19.05,18.51,18.64,18.88,18.92,18.93,18.12,18.34,18.72,18.82,18.74,18.22,18.46,18.76,18.26,18.13,18.24,18.46,18.58,17.30,18.38,18.08,18.24,17.68,18.34,18.46,18.65,18.23,18.70,18.52,18.79,18.83,18.18,18.51,19.01,19.08,19.08,18.99,19.02,19.07,19.20,19.27,19.06,19.01,19.28,19.46,19.30,18.94] xgrid = np.linspace(min(x), max(x),gridsize) ygrid = np.linspace(min(y), max(y),gridsize) xgrid, ygrid = np.meshgrid(xgrid, ygrid, indexing='ij') nsb_grid = griddata((x,y),skybrightness,(xgrid, ygrid), method='linear') plt.rc('ytick', labelsize=16) #colorbar font colors = plt.cm.get_cmap('RdYlBu') levels,steps = np.linspace(min(skybrightness), max(skybrightness)+0.3,graphlevels, retstep=True) ticks = np.linspace(min(skybrightness), max(skybrightness)+0.3,12) cax = ax.contourf(xgrid, ygrid, nsb_grid, levels=levels, cmap=colors) cbar = plt.colorbar(cax, fraction=0.046, pad=0.04, ticks=ticks) cbar.set_label(r'mag/arcsec$^2$') pax.set_theta_zero_location('N') pax.set_theta_direction(-1) pax.set_rmax(75) pax.set_yticks(range(10, 80, 20)) pax.set_xticklabels([r'N', r'NE', r'E', r'SE', r'S', r'SW', r'W', r'NW']) pax.grid(alpha=0.3)
Python matplotlib polar coordinate is not plotting as it is supposed to be
I am plotting from a CSV file that contains Cartesian coordinates and I want to change it to Polar coordinates, then plot using the Polar coordinates. Here is the code import matplotlib.pyplot as plt import pandas as pd import numpy as np import seaborn as sns df = pd.read_csv('test_for_plotting.csv',index_col = 0) x_temp = df['x'].values y_temp = df['y'].values df['radius'] = np.sqrt( np.power(x_temp,2) + np.power(y_temp,2) ) df['theta'] = np.arctan2(y_temp,x_temp) df['degrees'] = np.degrees(df['theta'].values) df['radians'] = np.radians(df['degrees'].values) ax = plt.axes(polar = True) ax.set_aspect('equal') ax.axis("off") sns.set(rc={'axes.facecolor':'white', 'figure.facecolor':'white','figure.figsize':(10,10)}) # sns.scatterplot(data = df, x = 'x',y = 'y', s= 1,alpha = 0.1, color = 'black',ax = ax) sns.scatterplot(data = df, x = 'radians',y = 'radius', s= 1,alpha = 0.1, color = 'black',ax = ax) plt.tight_layout() plt.show() Here is the dataset If you run this command using polar = False and use this line to plot sns.scatterplot(data = df, x = 'x',y = 'y', s= 1,alpha = 0.1, color = 'black',ax = ax) it will result in this picture now after setting polar = True and run this line to plot sns.scatterplot(data = df, x = 'radians',y = 'radius', s= 1,alpha = 0.1, color = 'black',ax = ax) It is supposed to give you this But it is not working as if you run the actual code the shape in the Polar format is the same as Cartesian which does not make sense and it does not match the picture I showed you for polar (If you are wondering where did I get the second picture from, I plotted it using R) I would appreciate your help and insights and thanks in advance!
For a polar plot, the "x-axis" represents the angle in radians. So, you need to switch x and y, and convert the angles to radians (I also added ax=ax, as the axes was created explicitly): import matplotlib.pyplot as plt import pandas as pd import numpy as np import seaborn as sns data = {'radius': [0, 0.5, 1, 1.5, 2, 2.5], 'degrees': [0, 25, 75, 155, 245, 335]} df_temp = pd.DataFrame(data) ax = plt.axes(polar=True) sns.scatterplot(x=np.radians(df_temp['degrees']), y=df_temp['radius'].to_numpy(), s=100, alpha=1, color='black', ax=ax) for deg, y in zip(df_temp['degrees'], df_temp['radius']): x = np.radians(deg) ax.axvline(x, color='skyblue', ls=':') ax.text(x, y, f' {deg}', color='crimson') ax.set_rlabel_position(-15) # Move radial labels away from plotted dots plt.tight_layout() plt.show() About your new question: if you have an xy plot, and you convert these xy values to polar coordinates, and then plot these on a polar plot, you'll get again the same plot. After some more testing with the data, I decided to create the plot directly with matplotlib, as seaborn makes some changes that don't have exactly equal effects across seaborn and matplotlib versions. What seems to be happening in R: The angles (given by "x") are spread out to fill the range (0,2 pi). This either requires a rescaling of x, or change how the x-values are mapped to angles. One way to get this, is subtracting the minimum. And with that result divide by the new maximum and multiply by 2 pi. The 0 of the angles it at the top, and the angles go clockwise. The following code should create the plot with Python. You might want to experiment with alpha and with s in the scatter plot options. (Default the scatter dots get an outline, which often isn't desired when working with very small dots, and can be removed by lw=0.) ax = plt.axes(polar=True) ax.set_aspect('equal') ax.axis('off') x_temp = df['x'].to_numpy() y_temp = df['y'].to_numpy() x_temp -= x_temp.min() x_temp = x_temp / x_temp.max() * 2 * np.pi ax.scatter(x=x_temp, y=y_temp, s=0.05, alpha=1, color='black', lw=0) ax.set_rlim(y_temp.min(), y_temp.max()) ax.set_theta_zero_location("N") # set zero at the north (top) ax.set_theta_direction(-1) # go clockwise plt.show() At the left the resulting image, at the right using the y-values for coloring (ax.scatter(..., c=y_temp, s=0.05, alpha=1, cmap='plasma_r', lw=0)):
Aligning data (contourf) on Basemap
I've started working with Basemap, which seems potentially very useful. If I plot some global data on a latitude/longitude grid as filled contours, it works great: Iff I leave the lat_0 and lon_0 as zero. Once I change the center location, the map moves but the data doesn't. I would be grateful for advice. I've created a simple version of the code I'm using, with some simple sample data that illustrates the problem. The values should be (are) large at the equator but small at the poles. If you run the code with lat_0 and lon_0 = 0, it works fine. But if you change the center location to a different coordinate, the same pattern/data is presented even though the map has moved. from mpl_toolkits.basemap import Basemap, cm import matplotlib.pyplot as plt import numpy as np # create data lat = np.linspace(-90,90,num=180) lon = np.linspace(-180,180,num=361) h2o_north = np.linspace(1,65,num=90) h2o_south = np.flipud(h2o_north) h2o = np.append(h2o_north,h2o_south) data = np.transpose(np.tile(h2o,(len(lon),1))) # create figure and axes instances fig = plt.figure(figsize=(10,10)) ax = fig.add_axes([0.1,0.1,0.8,0.8]) # create map m = Basemap(projection='ortho',lon_0=-50,lat_0=50,resolution='l') # draw coastlines and country boundaries m.drawcoastlines() m.drawcountries() # draw parallels parallels = np.arange(-90.,90,10.) m.drawparallels(parallels) # draw meridians meridians = np.arange(180.,360.,10.) m.drawmeridians(meridians) ny = data.shape[0] nx = data.shape[1] lons, lats = m.makegrid(nx, ny) # get lat/lons of ny by nx evenly space grid x, y = m(lons, lats) # compute map projection coordinates # draw filled contours. clevs = np.linspace(0,70,num=281) cs = m.contourf(x,y,data,clevs,cmap=plt.cm.jet) # colorbar cbar = m.colorbar(cs,location='bottom',pad="5%",ticks=np.linspace(0,70,15)) cbar.set_label('Scale of the data') plt.title('Some global data', fontsize=14)
Use np.meshgrid() to create the meshgrid of lon-lat, then, convert it to projection coordinates, and the data are ready to generate contours and plot. Here is the working code: from mpl_toolkits.basemap import Basemap import matplotlib.pyplot as plt import numpy as np # data for z (2D array) h2o_north = np.linspace(1, 65, num=90) h2o_south = np.flipud(h2o_north) h2o = np.append(h2o_north, h2o_south) data = np.transpose(np.tile(h2o, (len(h2o_north), 1))) # create figure and axes instances fig = plt.figure(figsize=(8, 8)) ax = fig.add_subplot() # create basemap instance m = Basemap(projection='ortho', lon_0=-50, lat_0=50, resolution='c', ax=ax) # create meshgrid covering the whole globe with ... # conforming dimensions of the `data` lat = np.linspace(-90, 90, data.shape[0]) lon = np.linspace(-180, 180, data.shape[1]) xs, ys = np.meshgrid(lon, lat) # basic mesh in lon, lat (degrees) x, y = m(xs, ys) # convert (lon,lat) to map (x,y) # draw filled contours clevs = np.linspace(0, np.max(data), 60) cs = m.contourf(x, y, data, clevs, cmap=plt.cm.jet) m.drawcoastlines() m.drawcountries() m.drawmeridians(range(-180, 180, 30)) m.drawparallels(range(-90, 90, 30)) # draw colorbar cbar = m.colorbar(cs, location='bottom', pad="5%", ticks=np.linspace(0, np.max(data), 5)) cbar.set_label('Scale of the data') plt.show() The resulting plot: