share
Stack OverflowShade 'cells' in polar plot with matplotlib
[+11] [3] Manuel Ebert
[2012-05-31 16:09:36]
[ python plot matplotlib ]
[ https://stackoverflow.com/questions/10837296/shade-cells-in-polar-plot-with-matplotlib ]

I've got a bunch of regularly distributed points (θ = n*π/6, r=1...8), each having a value in [0, 1]. I can plot them with their values in matplotlib using

polar(thetas, rs, c=values)

But rather then having just a meagre little dot I'd like to shade the corresponding 'cell' (ie. everything until halfway to the adjacent points) with the colour corresponding to the point's value:

Polar plot with shaded cells

(Note that here my values are just [0, .5, 1], in really they will be everything between 0 and 1. Is there any straight-forward way of realising this (or something close enough) with matplotlib? Maybe it's easier to think about it as a 2D-histogram?

[+13] [2012-06-01 10:22:56] fraxel

This can be done quite nicely by treating it as a polar stacked barchart:

import matplotlib.pyplot as plt
import numpy as np
from random import choice

fig = plt.figure()
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True)

for i in xrange(12*8):
    color = choice(['navy','maroon','lightgreen'])
    ax.bar(i * 2 * np.pi / 12, 1, width=2 * np.pi / 12, bottom=i / 12,
           color=color, edgecolor = color)
plt.ylim(0,10)
ax.set_yticks([])
plt.show()

Produces:

enter image description here


Haha, nice solution indeed! Just have to pick the color according to the value, but otherwise exactly what I need, and in the shortest possible way. JAB's solut and Joe's solutions are a tad ore generic, though. - Manuel Ebert
Oh, nice. Couldn't you also set edgecolor='None' in the bar() call, though? - JAB
@JAB - You'd think that ought to work, but it produces an entirely blank plot! Must be a bug (In my version at least). - fraxel
Well that's interesting. Can't test it out myself, unfortunately, as I don't have access to a matplotlib-equipped computer at the moment. - JAB
1
[+12] [2012-05-31 17:38:47] Joe Kington [ACCEPTED]

Sure! Just use pcolormesh on a polar axes.

E.g.

import matplotlib.pyplot as plt
import numpy as np

# Generate some data...
# Note that all of these are _2D_ arrays, so that we can use meshgrid
# You'll need to "grid" your data to use pcolormesh if it's un-ordered points
theta, r = np.mgrid[0:2*np.pi:20j, 0:1:10j]
z = np.random.random(theta.size).reshape(theta.shape)


fig, (ax1, ax2) = plt.subplots(ncols=2, subplot_kw=dict(projection='polar'))


ax1.scatter(theta.flatten(), r.flatten(), c=z.flatten())
ax1.set_title('Scattered Points')

ax2.pcolormesh(theta, r, z)
ax2.set_title('Cells')

for ax in [ax1, ax2]:
    ax.set_ylim([0, 1])
    ax.set_yticklabels([])

plt.show()

enter image description here

If your data isn't already on a regular grid, then you'll need to grid it to use pcolormesh.

It looks like it's on a regular grid from your plot, though. In that case, gridding it is quite simple. If it's already ordered, it may be as simple as calling reshape. Otherwise, a simple loop or exploiting numpy.histogram2d with your z values as weights will do what you need.


pcolor() works too. (Would've had my post done first if I hadn't taken the time to try to smooth the resultant rectangles... oh well.) - JAB
It's much less efficient for regular grids, though. Don't use it if your data is on a regular grid. - Joe Kington
You used to be able to smooth the rectangles by passing in a resolution keyword argument to the polar axes during initialization, but that's now ignored, apparently... - Joe Kington
If you have an example with smoothed rectangles, feel free to post it! It'd be a better answer than mine. - Joe Kington
Spent far too much time on it... but it's finally (mostly) done. Posted as an answer. - JAB
2
[+4] [2012-05-31 20:19:51] JAB

Well, it's fairly unpolished overall, but here's a version that rounds out the sections.

from matplotlib.pylab import *
ax = subplot(111, projection='polar')

# starts grid and colors
th = array([pi/6 * n for n in range(13)]) # so n = 0..12, allowing for full wrapping
r = array(range(9)) # r = 0..8
c = array([[random_integers(0, 10)/10 for y in range(th.size)] for x in range(r.size)])

# The smoothing
TH = cbook.simple_linear_interpolation(th, 10)

# Properly padding out C so the colors go with the right sectors (can't remember the proper word for such segments of wedges)
# A much more elegant version could probably be created using stuff from itertools or functools
C = zeros((r.size, TH.size))
oldfill = 0
TH_ = TH.tolist()

for i in range(th.size):
    fillto = TH_.index(th[i])

    for j, x in enumerate(c[:,i]):
        C[j, oldfill:fillto].fill(x)

    oldfill = fillto

# The plotting
th, r = meshgrid(TH, r)
ax.pcolormesh(th, r, C)
show()

THanks for going the extra mile, I really appreciate it! - Manuel Ebert
@Nkosinathi: You're quite welcome. And luckily for me, though I didn't think about it while working on the above, I realized that I could use it for a task I'm doing for work. - JAB
3