4
votes

I want a line (Line2D) object to move with the current cursor position on several axes of a figure. The way I'm doing it now is to re-draw the whole figure each time the cursor moves, by calling

fig.canvas.draw()

My figure consists in 14 panels among which 10 has a line which must move with the cursor, and doing this is very long.

I was wondering how to update only the lines and not redrawing the whole thing.

So I've tried to use

ax.draw_artist(line)

but this crashes. Here is a small example :

fig,ax =  subplots()
line = Line2D([0.3,0.3],[0.1,0.8])
ax.add_artist(line)
fig.canvas.draw()

#here I see the line on the figure ok

# I update the position of the line
line.set_xdata([0.6,0.8])

# now draw the line (this should add another one (*))
ax.draw_artist(line)

this last line causes the following error:

--------------------------------------------------------------------------- RuntimeError Traceback (most recent call last) in () ----> 1 ax.draw_artist(line)

/Users/Heimdall/anaconda/lib/python2.7/site-packages/matplotlib/axes.pyc in draw_artist(self, a) 2096 """ 2097 assert self._cachedRenderer is not None -> 2098 a.draw(self._cachedRenderer) 2099 2100 def redraw_in_frame(self):

/Users/Heimdall/anaconda/lib/python2.7/site-packages/matplotlib/artist.pyc in draw_wrapper(artist, renderer, *args, **kwargs) 53 def draw_wrapper(artist, renderer, *args, **kwargs): 54 before(artist, renderer) ---> 55 draw(artist, renderer, *args, **kwargs) 56 after(artist, renderer) 57

/Users/Heimdall/anaconda/lib/python2.7/site-packages/matplotlib/lines.pyc in draw(self, renderer) 524 525 renderer.open_group('line2d', self.get_gid()) --> 526 gc = renderer.new_gc() 527 self._set_gc_clip(gc) 528

/Users/Heimdall/anaconda/lib/python2.7/site-packages/matplotlib/backends/backend_macosx.pyc in new_gc(self) 95 96 def new_gc(self): ---> 97 self.gc.save() 98 self.gc.set_hatch(None) 99 self.gc._alpha = 1.0

RuntimeError: CGContextRef is NULL

I'm not sure where this error comes from??

Also, I've seen that I was supposed to somehow save the canvas before the first line is drawn and restore it each time I re draw it, so only one line appears. I've seen this could be done with :

 background = canvas.copy_from_bbox(ax.bbox)

and restore it with

canvas.restore_region(background)

however I have neither of these two methods in the object 'canvas'. Is this a problem with the MacOSX backend?

I have matplotlib 1.3.1 installed with the distribution anaconda on macOS 10.9.

also I've been told I could use :

fig.canvas.blit(line.clipbox)

to draw the line at its new position, but that does absolutely nothing.

1
There are a lot of limitations with the OSX backend. As you've noticed, it doesn't support blitting. (Also see: github.com/matplotlib/matplotlib/issues/531 ) Honestly, it's really best to avoid using the OSX backend unless you really need it. - Joe Kington
That's what I was starting to think... I'm not sure how to use another backend. I've tried : import matplotlib as mplt mpl.use('Qt4Agg') for instance.. and that gave me errors too (missing 'sip', which by the way failed to install) - MCF
It will depend on how you installed matplotlib. Interactive backends (e.g. TkAgg, OSX, Qt4Agg, etc) are built if their respective gui toolkits are available. Your best bet is the TkAgg backend (the default on most platforms). However, there are often problems with Apple's Tk (I don't remember the details), so your python install may not have Tk available. For the other backends, you'll need to install the gui toolkit (and the python bindings for it) and rebuild matplotlib. (Matplotlib on OSX is more painful than it should be.) - Joe Kington
My matplotlib comes with the "anaconda" distribution (docs.continuum.io/anaconda). Not sure what backend is included - MCF

1 Answers

0
votes

so the only solution I found is to give up anaconda and re-install everything with macports and with the backend qt4.

sudo port install py27-matplotlib +qt4