tags:

views:

70

answers:

3

The following generates a plot with three data points, at (0, 0), (0, 0.5), and (1, 1). Only that portion of the plotted points (small circles) which lie inside the plot area is visible, so I see quarter-circles in the corners, and a half circle along the left spine.

Is there a trick I can use to make all the points fully visible, so they are not clipped within the axes frame?

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111)
ax.plot([0, 0, 1], [0, 0.5, 1], 'o')
fig.canvas.print_figure('test.png')

Edit: Amro's suggestion -- the obvious approach -- is not the preferred approach as these are for ROC graphs (conventionally drawn with a box from 0 to 1 on both axes). If I could trick matplotlib into producing results similar to the many at http://www.google.com/search?q=roc+plot which have a box tightly around 0..1 on both axes, yet have points drawn on top of the axis lines as many of them do, that would be optimal.

Edit 2: I'm guessing this can be done using "spine placement" (new as of MPL 0.99), with the plot area enlarged slightly as Amro suggested, but then with the spines repositioned slightly to be along both 0 axes. I'll experiment with this and post an answer if it works, though feel free to beat me to it.

+1  A: 

You can extend the axes limits a bit in all directions:

ax = fig.add_subplot(111, xlim=(-0.1,1.1), ylim=(-0.1,1.1))

alt text

Amro
Thanks for the suggestion but, unfortunately, I believe that would be jarringly unconventional for the type of plot involved. See the many examples at http://www.google.com/images?q=roc+plot
Peter Hansen
A: 

I combined my idea using the new spine.set_position() capability with Amro's suggestion to expand the bounds slightly. The following works with only with matplotlib 1.0 or later, as it relies on the new spine.set_bounds() call. (I believe Amro's idea needed 1.0 or later as well, since the xlim/ylim kwargs did nothing for me with 0.99.1.)

fig = Figure()
canvas = FigureCanvas(fig)
ax = fig.add_subplot(111, xlim=(-0.1, 1.1), ylim=(-0.1, 1.1))
ax.plot([0, 0, 1], [0, 0.5, 1], 'o')
for side in 'left bottom top right'.split():
    ax.spines[side].set_position('zero')
    ax.spines[side].set_bounds(0, 1)
canvas.print_figure('test.png')

I'd still be quite interested to hear if there's a different approach, but my guess after much googling is that matplotlib has a basic restriction around this area: all data is tightly clipped by the region defined for the axis.

Peter Hansen
+4  A: 

You can turn the clipping off, either in the plot command, or in the artist objects returned by a call to "plot".

First, here's the figure, with extra big symbols so it's clear:

alt text

In the plot command you can do

ax.plot([0, 0, 1], [0, 0.5, 1], 'o', clip_on=False, markersize=20)

or you could have

p = ax.plot([0, 0, 1], [0, 0.5, 1], 'o', markersize=20)
for m in p:
    m.set_clip_on(False)
tom10
I need to add zorder=3 as well, so the points appear over the spines (and, if present, grid) instead of just peeking out from underneath, but this is the "trick" I needed. Thank you! :)
Peter Hansen