I'm trying to plot some data on the world map, which can be centered either near the Atlantic (i.e. 180°W–180°E) or at the Pacific (i.e. 0°–360°). Here's the program (with fictitious data):
import argparse
import numpy as np
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
from cartopy.mpl.gridliner import LONGITUDE_FORMATTER, LATITUDE_FORMATTER
parser = argparse.ArgumentParser()
parser.add_argument('--center', choices=['atlantic', 'pacific'], default='atlantic')
parser.add_argument('--outfile', default='plot.png')
args = parser.parse_args()
lat = np.linspace(-89.95, 89.95, 1800)
if args.center == 'atlantic':
lon = np.linspace(-179.95, 179.95, 3600)
clon = 0
else:
lon = np.linspace(0.05, 359.95, 3600)
clon = 180
x, y = np.meshgrid(lon, lat)
z = np.sin(x / 180 * np.pi) * np.sin(y / 180 * np.pi)
fig = plt.figure(figsize=(21, 7))
crs = ccrs.PlateCarree(central_longitude=clon)
ax = plt.axes(projection=crs)
ax.coastlines(resolution='110m', color='white', linewidth=2)
gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
gl.xformatter = LONGITUDE_FORMATTER
gl.yformatter = LATITUDE_FORMATTER
gl.xlabel_style = {'size': 16, 'color': 'black'}
gl.ylabel_style = {'size': 16, 'color': 'black'}
plt.contourf(x, y, z, cmap='RdYlBu_r')
cb = plt.colorbar(ax=ax, orientation='vertical', pad=0.02, aspect=16, shrink=0.8)
cb.ax.tick_params(labelsize=16)
fig.savefig(args.outfile, bbox_inches='tight', pad_inches=0.1)
However, when I switch from --center=atlantic to --center=pacific, only the coastlines move, while the X-axis and the data do not, resulting in an inconsistent plot. (With my fictitious data, North America should be in blue and Asia should be in red.)
--center=atlantic:
--center=pacific:
How can I make a correct plot that's centered at the Pacific?
It looks like I need the following changes:
Have a vanilla PlateCarree object (in addition to the existing one with central_longitude set) and use it in all cases except the call to plt.axes. (I don't understand why, but I find that it works.)
Add a call to ax.set_extent, also with the vanilla PlateCarree object.
Use transform in plt.contourf, also with the vanilla PlateCarree object.
Here's the diff from the original code:
## -23,0 +24 ##
+crs0 = ccrs.PlateCarree()
## -25,0 +27 ##
+ax.set_extent([lon[0], lon[-1], lat[0], lat[-1]], crs=crs0)
## -28 +30 ##
-gl = ax.gridlines(crs=crs, draw_labels=True, linewidth=1, color='black', linestyle='--')
+gl = ax.gridlines(crs=crs0, draw_labels=True, linewidth=1, color='black', linestyle='--')
## -34 +36 ##
-plt.contourf(x, y, z, cmap='RdYlBu_r')
+plt.contourf(x, y, z, cmap='RdYlBu_r', transform=crs0)
This produces 180°W and 180°E overwritten on top of each other. As a quick fix, I did this:
import matplotlib.ticker as mticker
# Fix LONGITUDE_FORMATTER so that either +180 or -180 returns just '180°',
# instead of '180°E' or '180°W'.
LONGITUDE_FORMATTER_NEW = mticker.FuncFormatter(
lambda v, pos: '180\u00B0' if abs(v) == 180 else LONGITUDE_FORMATTER.func(v, pos)
)
so that the identical strings 180° are overwritten at the same position on top of each other, minimizing the visual effect of the problem.
(LONGITUDE_FORMATTER doesn't handle anything beyond [−180, +180] properly, either, but I choose not to go into that here.)
Here's the result:
--center=atlantic:
--center=pacific:
Related
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:-
from mplsoccer.pitch import Pitch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import kde
np.random.seed(19680801)
plt.style.use('dark_background')
fields = ['id', 'minute', 'result', 'X1', 'Y','xG','h_a','situation','season',
'shotType','X']
df=pd.read_csv('shots.csv', skipinitialspace=True, usecols=fields)
df1 = pd.DataFrame({'A':df.Y,'B':df.X} )
a=(df1.to_numpy())
x, y = a.T
k = kde.gaussian_kde(a.T)
nbins=50
xi, yi = np.mgrid[x.min():x.max():nbins*1j, y.min():y.max():nbins*1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
pitch = Pitch(orientation='vertical',pitch_type='metricasports', view='half',
linewidth=2, line_zorder=1,
line_color= '#94A7AE',pitch_length=105, pitch_width=68,pad_bottom=0)
fig, ax = pitch.draw()
ax.pcolormesh(xi, yi, zi.reshape(xi.shape), shading='gouraud', cmap='Reds',facecolor='black'
)
ax.set_xlim(ax.get_xlim()[::-1])
ax.yaxis.tick_right()
plt.axis('off')
plt.show()
Output Plot here
I want the only red-colored density plot, not the white rectangular background frame. How to make the frame the same as my background?
Here is an approach using a colormap with an "under" color of 'none'. By setting vmin to a cut-off value, the cells with a lower value will get the "under" color ('none' stands for fully transparent). To get an idea of the values, temporarily a colorbar can be added. The values depend strongly on the extension of the x and y values (the integral of the kde is 1, so over a small domain the values need to be high enough).
from mplsoccer.pitch import Pitch
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import kde
from copy import copy
np.random.seed(19680801)
plt.style.use('dark_background')
# first create some random toy data roughly mimicking the given plot
x = np.random.randn(100, 20).cumsum(axis=0).flatten()
y = np.random.randn(100, 20).cumsum(axis=0).flatten()
x = x * 0.04 + 0.5
y = y * 0.01 + 0.9
k = kde.gaussian_kde([x, y])
nbins = 50
xi, yi = np.mgrid[x.min():x.max():nbins * 1j, y.min():y.max():nbins * 1j]
zi = k(np.vstack([xi.flatten(), yi.flatten()]))
pitch = Pitch(orientation='vertical', pitch_type='metricasports', view='half',
linewidth=2, line_zorder=1,
line_color='#94A7AE', pitch_length=105, pitch_width=68, pad_bottom=0)
fig, ax = pitch.draw()
cmap = copy(plt.get_cmap('Reds'))
cmap.set_under('none')
pmesh = ax.pcolormesh(xi, yi, zi.reshape(xi.shape), shading='gouraud', cmap=cmap, vmin=5, facecolor='black')
# fig.colorbar(pmesh, ax=ax) # to temporarily get an idea of the values
ax.invert_xaxis()
ax.yaxis.tick_right()
plt.axis('off')
plt.show()
I'm trying to adapt the Cartopy example plot for circular South Polar Stereographic plots to the North Pole and add data to it. I have a couple questions.
First, in the example code, the land feature is added before the ocean feature. When I did that, I got a map with only ocean. I reversed the order of the call in the code below and get a map with land and ocean. Why did the other order work with the South Polar example?
Second, and more importantly, I can't figure out why my pcolormesh call isn't having any effect.
I'm using Python 2.7.7, matplotlib 1.5.1, and Cartopy 0.15.1.
import matplotlib.path as mpath
import matplotlib.pyplot as plt
import numpy as np
import cartopy.crs as ccrs
import cartopy.feature
lats = np.linspace(60,90,30)
lons = np.linspace(0,360,200)
X,Y = np.meshgrid(lons,lats)
Z = np.random.normal(size = X.shape)
def main():
fig = plt.figure(figsize=[10, 5])
ax = plt.subplot(1, 1, 1, projection=ccrs.NorthPolarStereo())
fig.subplots_adjust(bottom=0.05, top=0.95,
left=0.04, right=0.95, wspace=0.02)
# Limit the map to -60 degrees latitude and below.
ax.set_extent([-180, 180, 60, 60], ccrs.PlateCarree())
ax.gridlines()
ax.add_feature(cartopy.feature.OCEAN)
ax.add_feature(cartopy.feature.LAND)
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax.set_boundary(circle, transform=ax.transAxes)
ax.pcolormesh(X,Y,Z,transform=ccrs.PlateCarree())
plt.show()
if __name__ == '__main__':
main()
Your code leaves cartopy to dictate the order of feature plots on the map, as a result, some features can be hidden with no clues. It is possible to specify the order of plots explicitly.
The order of features plot is controlled by zorder, which can be specified with zorder=integer in most plotting statements. Here is a modified code that produces a better plot.
# your data
lats = np.linspace(60, 90, 30)
lons = np.linspace(0, 360, 160)
X,Y = np.meshgrid(lons, lats)
Z = np.random.normal(size = X.shape)
# new data for pcolormesh plot
latz = np.linspace(75, 90, 15)
lonz = np.linspace(0, 360, 160)
X1,Y1 = np.meshgrid(lonz, latz)
Z1 = np.random.normal(size = X1.shape)
def main():
fig = plt.figure(figsize=[10, 10])
ax = plt.subplot(1, 1, 1, projection=ccrs.NorthPolarStereo())
fig.subplots_adjust(bottom=0.05, top=0.95,
left=0.04, right=0.95, wspace=0.02)
# Limit the map to -60 degrees latitude and below.
ax.set_extent([-180, 180, 60, 60], ccrs.PlateCarree())
ax.gridlines()
# zorder can be used to arrange what is on top
ax.add_feature(cartopy.feature.LAND, zorder=4) # land is specified to plot above ...
ax.add_feature(cartopy.feature.OCEAN, zorder=1) # ... the ocean
# Compute a circle in axes coordinates, which we can use as a boundary
# for the map. We can pan/zoom as much as we like - the boundary will be
# permanently circular.
theta = np.linspace(0, 2*np.pi, 100)
center, radius = [0.5, 0.5], 0.5
verts = np.vstack([np.sin(theta), np.cos(theta)]).T
circle = mpath.Path(verts * radius + center)
ax.set_boundary(circle, transform=ax.transAxes)
# pcolormesh is specified to plot on top of the ocean but below land
ax.pcolormesh(X1, Y1, Z1, transform=ccrs.PlateCarree(), zorder=3)
plt.show()
if __name__ == '__main__':
main()
I have a sample script to generate a polar contour plot in matplotlib:
import os
import math
import numpy as np
import matplotlib.pyplot as plt
import mpl_toolkits.axisartist.floating_axes as floating_axes
from matplotlib.projections import PolarAxes
from mpl_toolkits.axisartist.grid_finder import FixedLocator, MaxNLocator, DictFormatter
import random
# ------------------------------------ #
def setup_arc_radial_axes(fig, rect, angle_ticks, radius_ticks, min_rad, max_rad):
tr = PolarAxes.PolarTransform()
pi = np.pi
grid_locator1 = FixedLocator([v for v, s in angle_ticks])
tick_formatter1 = DictFormatter(dict(angle_ticks))
grid_locator2 = FixedLocator([a for a, b in radius_ticks])
tick_formatter2 = DictFormatter(dict(radius_ticks))
grid_helper = floating_axes.GridHelperCurveLinear(tr,
extremes=((370.0*(pi/180.0)), (170.0*(pi/180.0)), max_rad, min_rad),
grid_locator1=grid_locator1,
grid_locator2=grid_locator2,
tick_formatter1=tick_formatter1,
tick_formatter2=tick_formatter2,
)
ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper)
fig.add_subplot(ax1)
ax1.grid(True)
# create a parasite axes whose transData in RA, cz
aux_ax = ax1.get_aux_axes(tr)
aux_ax.patch = ax1.patch
ax1.patch.zorder=0.9
#ax1.axis["left"].set_ticklabel_direction("+")
return ax1, aux_ax
# ------------------------------------ #
# write angle values to the plotting array
angles = []
for mic_num in range(38):
angle = float(mic_num)*(180.0/36.0)*(math.pi/180.0)+math.pi
angles.append(angle)
# ------------------------------------ #
### these are merely the ticks that appear on the plot axis
### these don't actually get plotted
angle_ticks = range(0,190,10)
angle_ticks_rads = [a*math.pi/180.0 for a in angle_ticks]
angle_ticks_rads_plus_offset = [a+math.pi for a in angle_ticks_rads]
angle_ticks_for_plot = []
for i in range(len(angle_ticks)):
angle_ticks_for_plot.append((angle_ticks_rads_plus_offset[i],r"$"+str(angle_ticks[i])+"$"))
# ------------------------------------ #
scale = 1.0
aspect = 1.50
height = 8.0
fig = plt.figure(1, figsize=(height*aspect*scale, height*scale))
fig.subplots_adjust(wspace=0.3, left=0.05, right=0.95, top=0.84)
fig.subplots_adjust()
plot_real_min = 30.0
plot_real_max = 100.0
plot_fake_min = 0.0
plot_fake_max = 5000.0
rad_tick_increment = 500.0
radius_ticks = []
for i in range(int(plot_fake_min),int(plot_fake_max)+int(rad_tick_increment),int(rad_tick_increment)):
plot_fake_val = ((i-plot_fake_min)/(plot_fake_max-plot_fake_min))*(plot_real_max-plot_real_min)+plot_real_min
radius_ticks.append((plot_fake_val, r"$"+str(i)+"$"))
ax2, aux_ax2 = setup_arc_radial_axes(fig, 111, angle_ticks_for_plot, radius_ticks, plot_real_min, plot_real_max)
azimuths = np.radians(np.linspace(0, 180, 91))
azimuths_adjusted = [ (x + math.pi) for x in azimuths ]
zeniths = np.arange(0, 5050, 50)
zeniths_adjusted = [((x-plot_fake_min)/(plot_fake_max-plot_fake_min))*(plot_real_max-plot_real_min)+plot_real_min for x in zeniths]
r, theta = np.meshgrid(zeniths_adjusted, azimuths_adjusted)
values = 90.0+5.0*np.random.random((len(azimuths), len(zeniths)))
aux_ax2.contourf(theta, r, values)
cbar = plt.colorbar(aux_ax2.contourf(theta, r, values), orientation='vertical')
cbar.ax.set_ylabel('Contour Value [Unit]', fontsize = 16)
plt.suptitle('Plot Title ', fontsize = 24, weight="bold")
plt.legend(loc=3,prop={'size':20})
plt.xlabel('Angle [deg]', fontsize=20, weight="bold")
plt.ylabel('Frequency [Hz]', fontsize=20, weight="bold")
# plt.show()
plt.savefig('test.png', dpi=100)
plt.close()
This script will generate a plot that looks something like:
My question is how can I plot with an alternate color bar scale? Is it possible to define a custom scale?
Something like a blue-white-red scale where deltas around a central value can easily be shown would be the best, something like:
You can create a custom scale, but matplotlib already has what you want. All you have to do is add an argument to contourf:
aux_ax2.contourf(theta, r, values, cmap = 'bwr')
If you don't like bwr, coolwarm and seismic are also blue to red. If you need to reverse the scale, just add _r to the colormap name. You can find more colormaps here: http://matplotlib.org/examples/color/colormaps_reference.html
I can't run your code, but I think you could solve your problem this way:
from matplotlib import pyplot as plt
import matplotlib as mpl
f = plt.figure(figsize=(5,10))
ax = f.add_axes([0.01, 0.01, 0.4, 0.95])
#here we create custom colors
cmap = mpl.colors.LinearSegmentedColormap.from_list(name='Some Data',colors=['b', 'w','w', 'r'])
cb = mpl.colorbar.ColorbarBase(ax, cmap=cmap, orientation='vertical')
cb.set_label('Some Data')
plt.show()
And if linear way is not what you are looking for here is some other types:
http://matplotlib.org/api/colors_api.html#module-matplotlib.colors
Here is my code to plot some data:
from scipy.interpolate import griddata
from numpy import linspace
import matplotlib.pyplot as plt
meanR = [9.95184937, 9.87947708, 9.87628496, 9.78414422,
9.79365258, 9.96168969, 9.87537519, 9.74536093,
10.16686878, 10.04425475, 10.10444126, 10.2917172 ,
10.16745917, 10.0235203 , 9.89914 , 10.11263505,
9.99756449, 10.17861254, 10.04704248]
koord = [[1,4],[3,4],[1,3],[3,3],[2,3],[1,2],[3,2],[2,2],[1,1],[3,1],[2,1],[1,0],[3,0],[0,3],[4,3],[0,2],[4,2],[0,1],[4,1]]
x,y=[],[]
for i in koord:
x.append(i[0])
y.append(i[1])
z = meanR
xi = linspace(-2,6,300);
yi = linspace(-2,6,300);
zi = griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
CS = plt.contourf(xi,yi,zi,15,cmap=plt.cm.jet)
plt.scatter(x,y,marker='o',c='b',s=15)
plt.xlim(min(x),max(x))
plt.ylim(min(y),max(y))
plt.show()
In result we have:
How can I inscribe it in a circle? something like this
Because you don't seem to need any axes you can also use a normal projection, remove the axes and draw a circle. I had some fun and added some bonus ears, a nose and a color bar. I annotated the code, I hope it is clear.
from __future__ import print_function
from __future__ import division
from __future__ import absolute_import
import scipy.interpolate
import numpy
import matplotlib
import matplotlib.pyplot as plt
# close old plots
plt.close("all")
# some parameters
N = 300 # number of points for interpolation
xy_center = [2,2] # center of the plot
radius = 2 # radius
# mostly original code
meanR = [9.95184937, 9.87947708, 9.87628496, 9.78414422,
9.79365258, 9.96168969, 9.87537519, 9.74536093,
10.16686878, 10.04425475, 10.10444126, 10.2917172 ,
10.16745917, 10.0235203 , 9.89914 , 10.11263505,
9.99756449, 10.17861254, 10.04704248]
koord = [[1,4],[3,4],[1,3],[3,3],[2,3],[1,2],[3,2],[2,2],[1,1],[3,1],[2,1],[1,0],[3,0],[0,3],[4,3],[0,2],[4,2],[0,1],[4,1]]
x,y = [],[]
for i in koord:
x.append(i[0])
y.append(i[1])
z = meanR
xi = numpy.linspace(-2, 6, N)
yi = numpy.linspace(-2, 6, N)
zi = scipy.interpolate.griddata((x, y), z, (xi[None,:], yi[:,None]), method='cubic')
# set points > radius to not-a-number. They will not be plotted.
# the dr/2 makes the edges a bit smoother
dr = xi[1] - xi[0]
for i in range(N):
for j in range(N):
r = numpy.sqrt((xi[i] - xy_center[0])**2 + (yi[j] - xy_center[1])**2)
if (r - dr/2) > radius:
zi[j,i] = "nan"
# make figure
fig = plt.figure()
# set aspect = 1 to make it a circle
ax = fig.add_subplot(111, aspect = 1)
# use different number of levels for the fill and the lines
CS = ax.contourf(xi, yi, zi, 60, cmap = plt.cm.jet, zorder = 1)
ax.contour(xi, yi, zi, 15, colors = "grey", zorder = 2)
# make a color bar
cbar = fig.colorbar(CS, ax=ax)
# add the data points
# I guess there are no data points outside the head...
ax.scatter(x, y, marker = 'o', c = 'b', s = 15, zorder = 3)
# draw a circle
# change the linewidth to hide the
circle = matplotlib.patches.Circle(xy = xy_center, radius = radius, edgecolor = "k", facecolor = "none")
ax.add_patch(circle)
# make the axis invisible
for loc, spine in ax.spines.iteritems():
# use ax.spines.items() in Python 3
spine.set_linewidth(0)
# remove the ticks
ax.set_xticks([])
ax.set_yticks([])
# Add some body parts. Hide unwanted parts by setting the zorder low
# add two ears
circle = matplotlib.patches.Ellipse(xy = [0,2], width = 0.5, height = 1.0, angle = 0, edgecolor = "k", facecolor = "w", zorder = 0)
ax.add_patch(circle)
circle = matplotlib.patches.Ellipse(xy = [4,2], width = 0.5, height = 1.0, angle = 0, edgecolor = "k", facecolor = "w", zorder = 0)
ax.add_patch(circle)
# add a nose
xy = [[1.5,3], [2,4.5],[2.5,3]]
polygon = matplotlib.patches.Polygon(xy = xy, facecolor = "w", zorder = 0)
ax.add_patch(polygon)
# set axes limits
ax.set_xlim(-0.5, 4.5)
ax.set_ylim(-0.5, 4.5)
plt.show()
If you replace the part where you do the plotting with:
fig = plt.figure()
ax = fig.add_subplot(111, polar=True)
CS = ax.contourf(xi,yi,zi,15,cmap=plt.cm.jet)
ax.scatter(x,y,marker='o',c='b',s=15)
ax.set_xlim(min(x),max(x))
ax.set_ylim(min(y),max(y))
you get this
To get what you want, you have to rescale the x, y, xi, yi such that the image is centered in zero. You might also need to convert to polar coordinates. Now I don't have time to provide more info, but I hope that this helps you in getting started