Search code examples
pythonmatplotlibpolar-coordinates

Contour density plot in matplotlib using polar coordinates


From a set of angle (theta) and radius (r) I drew a scatter plot using matplotlib:

fig = plt.figure()
ax = plt.subplot(111, polar=True)

ax.scatter(theta, r, color='None', edgecolor='red')

ax.set_rmax(1)   
plt.savefig("polar.eps",bbox_inches='tight')

Which gave me this figure

I now want to draw the density contour map on top of that, so I tried:

fig = plt.figure()
ax = plt.subplot(111, polar=True)

H, theta_edges, r_edges = np.histogram2d(theta, r)
cax = ax.contourf(theta_edges[:-1], r_edges[:-1], H, 10, cmap=plt.cm.Spectral)

ax.set_rmax(1)
plt.savefig("polar.eps",bbox_inches='tight')

Which gave me the following results that is obviously not what I wanted to do.

What am I doing wrong ?


Solution

  • I think that the solution to your problem is to define the bins arrays for your histogram (for instance a linspaced array between 0 and 2pi for theta and between 0 and 1 for r). This can be done with the bins or range arguments of function numpy.histogram

    I you do so, make sure that the theta values are all between 0 and 2pi by plotting theta % (2 * pi) instead of theta.

    Finally, you may choose to plot the middle of the bin edges instead of the left side of the bins as done in your example (use 0.5 * (r_edges[1:] + r_edges[:-1]) instead of r_edges[:-1])

    below is a suggestion of code

    import matplotlib.pyplot as plt
    import numpy as np
    
    #create the data 
    r1     = .2 + .2 * np.random.randn(200)
    theta1 = 0. + np.pi / 7. * np.random.randn(len(r1)) 
    r2     = .8 + .2 * np.random.randn(300)
    theta2 = .75 * np.pi + np.pi / 7. * np.random.randn(len(r2)) 
    r = np.concatenate((r1, r2))
    theta = np.concatenate((theta1, theta2))
    
    
    
    fig = plt.figure()
    ax = plt.subplot(111, polar=True)
    
    #define the bin spaces
    r_bins     = np.linspace(0., 1., 12)
    N_theta    = 36
    d_theta    = 2. * np.pi / (N_theta + 1.)
    theta_bins = np.linspace(-d_theta / 2., 2. * np.pi + d_theta / 2., N_theta)
    
    
    H, theta_edges, r_edges = np.histogram2d(theta % (2. * np.pi), r, bins = (theta_bins, r_bins))
    
    #plot data in the middle of the bins
    r_mid     = .5 * (r_edges[:-1] + r_edges[1:])
    theta_mid = .5 * (theta_edges[:-1] + theta_edges[1:])
    
    
    cax = ax.contourf(theta_mid, r_mid, H.T, 10, cmap=plt.cm.Spectral)
    ax.scatter(theta, r, color='k', marker='+')
    ax.set_rmax(1)
    plt.show()
    

    which should result as

    polar histogram