How to create a polar contour plot
Asked Answered
M

2

22

Update: I've done a full write-up of the way I found to do this on my blog at http://blog.rtwilson.com/producing-polar-contour-plots-with-matplotlib/ - you may want to check there first.

I'm trying to plot a polar contour plot in matplotlib. I've found various resources on the internet, (a) I can't seem to get my code to work and (b) many of the resources appear rather old, and I'm wondering if there is a better way now. For example, http://www.mail-archive.com/[email protected]/msg01953.html suggests that something may be done to improve things soon, and that was in 2006!

I'd love to be able to plot proper polar contour plots - like pcolor lets you do for its type of plot (see commented out section below), but I can't seem to find any way to do that, so I'm converting to cartesian co-ordinates first.

Anyway, I have the code that follows:

from pylab import *
import numpy as np

azimuths = np.arange(0, 360, 10)
zeniths = np.arange(0, 70, 10)
values = []

for azimuth in azimuths:
  for zenith in zeniths:
    print "%i %i" % (azimuth, zenith)
    # Run some sort of model and get some output
    # We'll just use rand for this example
    values.append(rand())

theta = np.radians(azimuths)

values = np.array(values)
values = values.reshape(len(zeniths), len(azimuths))

# This (from http://old.nabble.com/2D-polar-surface-plot-td28896848.html)
# works fine
##############
# Create a polar axes
# ax = subplot(111, projection='polar')
# pcolor plot onto it
# c = ax.pcolor(theta, zeniths, values)
# show()

r, t = np.meshgrid(zeniths, azimuths)

x = r*np.cos(t)
y = r*np.sin(t)

contour(x, y, values)

When I run that I get an error TypeError: Inputs x and y must be 1D or 2D.. I'm not sure why I get this, as both x and y are 2D. Am I doing something wrong?

Also, it seems rather clunky to be putting my values returned from my model into a list and then reshaping it. Is there a better way to do this?

Mopes answered 30/1, 2012 at 21:33 Comment(0)
A
26

You should just be able to use ax.contour or ax.contourf with polar plots just as you normally would... You have a few bugs in your code, though. You convert things to radians, but then use the values in degrees when you plot. Also, you're passing in r, theta to contour when it expects theta, r.

As a quick example:

import numpy as np
import matplotlib.pyplot as plt

#-- Generate Data -----------------------------------------
# Using linspace so that the endpoint of 360 is included...
azimuths = np.radians(np.linspace(0, 360, 20))
zeniths = np.arange(0, 70, 10)

r, theta = np.meshgrid(zeniths, azimuths)
values = np.random.random((azimuths.size, zeniths.size))

#-- Plot... ------------------------------------------------
fig, ax = plt.subplots(subplot_kw=dict(projection='polar'))
ax.contourf(theta, r, values)

plt.show()

enter image description here

Alic answered 31/1, 2012 at 16:20 Comment(6)
Thanks - that's very helpful. I've pretty much got it working now! Just one quick query - if that's ok. I have to loop through the azimuths and zeniths to run my model and get out my data (the model involves calling another python library) - is the way I'm doing it with a list, and then reshaping the array, a sensible way to do it? Is there a more pythonic way?Mopes
There are several ways, but if you don't know the size of the array before-hand, then building a list and turning it into an array at the end is a very good solution. There's also numpy.fromiter, which is nice if you're running into memory problems. As far as the nested for loops, you could replace them with itertools.product, but that's largely a matter of taste. If you could vectorize things to work with an array instead of a single value, you'd probably see a speedup. If you can't (due to the other library) then you can't, though.Alic
It is often cleaner to write a simple generator (Most likely a function using yield, in your case) instead of a more "spagetti-string" solution, though. Modular is better :)Alic
How to deal with this ugly interpolation drop along theta=0 axis?Haman
@JoeKington can I use the same approach for my question here - scicomp.stackexchange.com/questions/28058/…Likewise
@JoeKington do you know a way to add a colorbar here? Unfortunately when I try ax.colorbar() I get the error AttributeError: 'PolarAxesSubplot' object has no attribute 'colorbar'Mccall
Z
4

the shape of x, y and values must be the same. Your data shape is:

>>> x.shape, y.shape, values.shape
((36, 7), (36, 7), (7, 36))

so change contour(x, y, values) to contour(x, y, values.T).

Zodiac answered 31/1, 2012 at 2:3 Comment(1)
Thanks, that solved the problem. Do you have any ideas about the other parts of the question regarding the current best way to do polar contour plots in matplotlib?Mopes

© 2022 - 2024 — McMap. All rights reserved.