4

I have the following Python code which I am using to plot a filled contour plot:

  def plot_polar_contour(values, azimuths, zeniths):
  theta = np.radians(azimuths)
  zeniths = np.array(zeniths)

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

  r, theta = np.meshgrid(zeniths, np.radians(azimuths))
  fig, ax = subplots(subplot_kw=dict(projection='polar'))
  ax.set_theta_zero_location("N")
  ax.set_theta_direction(-1)
  cax = ax.contourf(theta, r, values, 30)
  autumn()
  cb = fig.colorbar(cax)
  cb.set_label("Pixel reflectance")
  show()

This gives me a plot like:

enter image description here

However, when I add the line ax.plot(0, 30, 'p') just before show() I get the following:

enter image description here

It seems that just adding that one point (which is well within the original axis range) screws up the axis range on the radius axis.

Is this by design, or is this a bug? What would you suggest doing to fix it? Do I need to manually adjust the axis ranges, or is there a way to stop the extra plot command doing this?

shift66
  • 11,760
  • 13
  • 50
  • 83
robintw
  • 27,571
  • 51
  • 138
  • 205

1 Answers1

5

If the axis auto-scaling mode isn't explicitly specified, plot will use "loose" autoscaling and contourf will use "tight" autoscaling.

The same things happens for non-polar axes. E.g.

import matplotlib.pyplot as plt
import numpy as np

plt.imshow(np.random.random((10,10)))
plt.plot([7], [7], 'ro')
plt.show()

You have a number of options.

  1. Explicitly call ax.axis('image') or ax.axis('tight') at some point in the code.
  2. Pass in scalex=False and scaley=False as keyword arguments to plot.
  3. Manually set the axis limits.

The easiest and most readable is to just explicitly call ax.axis('tight'), i.m.o.

Joe Kington
  • 275,208
  • 71
  • 604
  • 463
  • 3
    Placing `ax.autoscale(False)` after `ax.countourf` but before `ax.plot` is [another option](http://stackoverflow.com/a/9120929/190597). – unutbu Feb 21 '12 at 16:07
  • Thanks. Using `scalex=False` and `scaley=False` solves the problem, but I'd prefer to use `ax.axis('tight')` as it's a bit cleaner, but I can't get that to work. Where should I place the call to `ax.axis('tight')`? I've tried putting it before and after the call to `ax.plot` and before and after the call to `ax.contourf`. Any ideas? – robintw Feb 21 '12 at 16:10
  • @unutbu: Thanks, that works fine and is a bit more obvious than some of the other options. – robintw Feb 21 '12 at 16:11
  • @robintw - `ax.axis('tight')` will work anywhere in the code with `imshow`, but `contourf` does things a bit differently (I forgot about that...). `ax.axis('image')` or `ax.axis('tight')` should work fine if you put them after calling `plot`. – Joe Kington Feb 21 '12 at 16:19