I have data that represents values at interior points within a circle. I would like to create a heat map similar to http://matplotlib.org/examples/pylab_examples/image_interp.html. Anybody familiar with a method for doing this with a circle?
2 Answers
You can do this by using a polar projection on your axis. Note, that this will not work with imshow as per the example you gave. (See: http://en.it-usenet.org/thread/15998/715/) However you can still do interpolation and then plot a heat map. Below is a simple example:
from pylab import *
import numpy as np
from scipy.interpolate import griddata
#create 5000 Random points distributed within the circle radius 100
max_r = 100
max_theta = 2.0 * np.pi
number_points = 5000
points = np.random.rand(number_points,2)*[max_r,max_theta]
#Some function to generate values for these points,
#this could be values = np.random.rand(number_points)
values = points[:,0] * np.sin(points[:,1])* np.cos(points[:,1])
#now we create a grid of values, interpolated from our random sample above
theta = np.linspace(0.0, max_theta, 100)
r = np.linspace(0, max_r, 200)
grid_r, grid_theta = np.meshgrid(r, theta)
data = griddata(points, values, (grid_r, grid_theta), method='cubic',fill_value=0)
#Create a polar projection
ax1 = plt.subplot(projection="polar")
ax1.pcolormesh(theta,r,data.T)
plt.show()
Note that I have used a fill_value of 0, so any values in the grid that fall outside the convex shape of the random data will have the value of 0.
If you wish to do the same you will need to convert your data into polar coordinates before doing the same, (assuming your readings are in Cartesian coordinates). To do that you can use:
def convert_to_polar(x, y):
theta = np.arctan2(y, x)
r = np.sqrt(x**2 + y**2)
return theta, r
You may find the answers to these questions helpful too: image information along a polar coordinate system Adding a colorbar to a pcolormesh with polar projection
The first of those in particular has a really detailed answer.
I appreciate that this is an old question, but as I made use of the answer by Weir_Doe and developed it in a slightly different way, I thought I'd contribute my method in the hope that it helps someone else.
I was trying to do something similar, and collected results for r and theta in a systematic fashion, as such I ended up with a grid. Once you have a grid you can use a zoom to get a higher definition image.
from pylab import *
import numpy as np
from scipy.ndimage import zoom
import pandas as pd
max_r = 100
max_theta = 2.5 * np.pi
number_points = 5
#Generate a grid 100 x 100 r x theta
r = np.arange(0, max_r,max_theta/number_points)
theta = np.arange(0,max_theta,max_theta/number_points)
grid_r, grid_theta = np.meshgrid(r, theta)
#Generate random numbers for each grid point
values = (np.sin(grid_r)+np.cos(grid_theta)).flatten()
#I always find it easier to put it in a dataframe
df = pd.DataFrame(grid_r.flatten()).rename(columns={0:'r'})
df['theta'] = grid_theta.flatten()
df['values'] = values
df = df.pivot(index='theta', columns='r')
#printing the dataframe at this point is very helpful conceptually
#Create a polar projection
ax1 = plt.subplot(projection="polar")
ax1.pcolormesh(df.index,r,df.values.T)
plt.show()
#Zoom in to the grid, this interpolates the results onto a finer grid
#Here I chose a 10x finer grid, this is more efficient than to interpolate onto specified points
zoom_factor=10
zoomed_df = zoom(df, zoom_factor)
zoomed_index = zoom(theta, zoom_factor)
zoomed_columns = zoom(r, zoom_factor)
high_def_grid = pd.DataFrame(zoomed_df, index=zoomed_index, columns=zoomed_columns)
#Create a polar projection
ax1 = plt.subplot(projection="polar")
ax1.pcolormesh(high_def_grid.index,high_def_grid.columns,high_def_grid.values.T)
plt.show()
This results in 2 images, the pre-interpolate image:
And the post-interpolation plot:
like I say, this only works if the data is collected in a systematic way, but for scientific purposes, this will be the case.
Additionally, using a pandas dataframe is not a necessary step, but I find it conceptually much simpler when doing it this way.
Hope this helps.

- 76
- 4