Confusion about draw_artist

Hi,

We're using 'draw_artist' in an image viewer, and I just found that
our viewer is crashing using the macosx backend. Here's a minimal
example:

import matplotlib
matplotlib.use('macosx')
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1)
im = plt.imshow([[1, 2], [3, 4]])
fig.canvas.draw()
ax.draw_artist(im)

This generates:

Traceback (most recent call last):
  File "draw_artist.py", line 8, in <module>
    ax.draw_artist(im)
  File "/Users/mb312/dev_trees/matplotlib/lib/matplotlib/axes/_base.py",
line 2423, in draw_artist
    raise AttributeError(msg)
AttributeError: draw_artist can only be used after an initial draw
which caches the render

for the macosx backend, and works correctly for the tkagg backend.

I can't see any way to cache the renderer here - could someone give me
a pointer?

Cheers,

Matthew

Unless you have flagged the artist as `animated` (via `set_animated` or by
kwarg), it will be drawn as part of the next re-draw. You are better off
just changing the `fig.canvas.draw()` to `fig.canvas.draw_idle()` and
letting the GUI decide when to re-draw things.

If you want to get any performance gain from animated artists + draw_artist
you will need to use blitting (which will work with the OSX backend in 2.0).

Tom

···

On Wed, Nov 30, 2016 at 2:11 PM Matthew Brett <matthew.brett at gmail.com> wrote:

Hi,

We're using 'draw_artist' in an image viewer, and I just found that
our viewer is crashing using the macosx backend. Here's a minimal
example:

import matplotlib
matplotlib.use('macosx')
import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 1)
im = plt.imshow([[1, 2], [3, 4]])
fig.canvas.draw()
ax.draw_artist(im)

This generates:

Traceback (most recent call last):
  File "draw_artist.py", line 8, in <module>
    ax.draw_artist(im)
  File "/Users/mb312/dev_trees/matplotlib/lib/matplotlib/axes/_base.py",
line 2423, in draw_artist
    raise AttributeError(msg)
AttributeError: draw_artist can only be used after an initial draw
which caches the render

for the macosx backend, and works correctly for the tkagg backend.

I can't see any way to cache the renderer here - could someone give me
a pointer?

Cheers,

Matthew
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel at python.org
https://mail.python.org/mailman/listinfo/matplotlib-devel

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20170105/c1202187/attachment.html>

Hi,

Sorry to keep displaying my confusion on this one but...

Unless you have flagged the artist as `animated` (via `set_animated` or by
kwarg), it will be drawn as part of the next re-draw.

Adding `set_animated` doesn't help in the example above;

fig, ax = plt.subplots(1, 1)
ax.set_animated(True)
im = plt.imshow([[1, 2], [3, 4]])
fig.canvas.draw()
ax.draw_artist(im)

You are better off
just changing the `fig.canvas.draw()` to `fig.canvas.draw_idle()` and
letting the GUI decide when to re-draw things.

Changing to `fig.canvas.draw_idle()` above doesn't prevent the error
from `draw_artist`, but I guess I should not have expected it would.
So I guess my question is - how do I use `draw_artist` in this case?
Is there any way to make sure that the renderer is cached first?

If you want to get any performance gain from animated artists + draw_artist
you will need to use blitting (which will work with the OSX backend in 2.0).

Yup, the real code does use blitting, but thanks for the reminder,

Cheers,

Matthew

···

On Wed, Jan 4, 2017 at 6:58 PM, Thomas Caswell <tcaswell at gmail.com> wrote:

Hi,

···

On Thu, Jan 19, 2017 at 11:54 AM, Matthew Brett <matthew.brett at gmail.com> wrote:

Hi,

Sorry to keep displaying my confusion on this one but...

On Wed, Jan 4, 2017 at 6:58 PM, Thomas Caswell <tcaswell at gmail.com> wrote:

Unless you have flagged the artist as `animated` (via `set_animated` or by
kwarg), it will be drawn as part of the next re-draw.

Adding `set_animated` doesn't help in the example above;

fig, ax = plt.subplots(1, 1)
ax.set_animated(True)
im = plt.imshow([[1, 2], [3, 4]])
fig.canvas.draw()
ax.draw_artist(im)

You are better off
just changing the `fig.canvas.draw()` to `fig.canvas.draw_idle()` and
letting the GUI decide when to re-draw things.

Changing to `fig.canvas.draw_idle()` above doesn't prevent the error
from `draw_artist`, but I guess I should not have expected it would.
So I guess my question is - how do I use `draw_artist` in this case?
Is there any way to make sure that the renderer is cached first?

If you want to get any performance gain from animated artists + draw_artist
you will need to use blitting (which will work with the OSX backend in 2.0).

Yup, the real code does use blitting, but thanks for the reminder,

Again - sorry to persist - but I'd be really grateful for any advice,

Cheers,

Matthew

Sorry - again again - but can I nose this one up towards the surface?

Cheers,

Matthew

···

On Fri, Mar 3, 2017 at 11:19 PM, Matthew Brett <matthew.brett at gmail.com> wrote:

Hi,

On Thu, Jan 19, 2017 at 11:54 AM, Matthew Brett <matthew.brett at gmail.com> wrote:

Hi,

Sorry to keep displaying my confusion on this one but...

On Wed, Jan 4, 2017 at 6:58 PM, Thomas Caswell <tcaswell at gmail.com> wrote:

Unless you have flagged the artist as `animated` (via `set_animated` or by
kwarg), it will be drawn as part of the next re-draw.

Adding `set_animated` doesn't help in the example above;

fig, ax = plt.subplots(1, 1)
ax.set_animated(True)
im = plt.imshow([[1, 2], [3, 4]])
fig.canvas.draw()
ax.draw_artist(im)

You are better off
just changing the `fig.canvas.draw()` to `fig.canvas.draw_idle()` and
letting the GUI decide when to re-draw things.

Changing to `fig.canvas.draw_idle()` above doesn't prevent the error
from `draw_artist`, but I guess I should not have expected it would.
So I guess my question is - how do I use `draw_artist` in this case?
Is there any way to make sure that the renderer is cached first?

If you want to get any performance gain from animated artists + draw_artist
you will need to use blitting (which will work with the OSX backend in 2.0).

Yup, the real code does use blitting, but thanks for the reminder,

Again - sorry to persist - but I'd be really grateful for any advice,

The renderer is cached automatically the first time the figure is fully
rendered (typically delayed until it is shown on the screen). If your
artist is not marked as animated, then just try..exect the call to
`draw_artist`, as the artist will be drawn as part of the normal draw
process when the figure is drawn. If you have marked it as animated (which
you should if you are blitting) then you are going to need to have some
call backs in place for draw and resize events (as any 'animated' artists
will not be drawn if the figure is re-rendered from scratch by the GUI for
what ever reason and to re-grab the background if the window is resized) so
put the `draw_artist` in the callback (which comes out after the figure is
drawn so you will have a renderer at that point).

Tom

···

On Fri, Mar 24, 2017 at 10:27 AM Matthew Brett <matthew.brett at gmail.com> wrote:

On Fri, Mar 3, 2017 at 11:19 PM, Matthew Brett <matthew.brett at gmail.com> > wrote:
> Hi,
>
> On Thu, Jan 19, 2017 at 11:54 AM, Matthew Brett <matthew.brett at gmail.com> > wrote:
>> Hi,
>>
>> Sorry to keep displaying my confusion on this one but...
>>
>> On Wed, Jan 4, 2017 at 6:58 PM, Thomas Caswell <tcaswell at gmail.com> > wrote:
>>> Unless you have flagged the artist as `animated` (via `set_animated`
or by
>>> kwarg), it will be drawn as part of the next re-draw.
>>
>> Adding `set_animated` doesn't help in the example above;
>>
>> fig, ax = plt.subplots(1, 1)
>> ax.set_animated(True)
>> im = plt.imshow([[1, 2], [3, 4]])
>> fig.canvas.draw()
>> ax.draw_artist(im)
>>
>>> You are better off
>>> just changing the `fig.canvas.draw()` to `fig.canvas.draw_idle()` and
>>> letting the GUI decide when to re-draw things.
>>
>> Changing to `fig.canvas.draw_idle()` above doesn't prevent the error
>> from `draw_artist`, but I guess I should not have expected it would.
>> So I guess my question is - how do I use `draw_artist` in this case?
>> Is there any way to make sure that the renderer is cached first?
>>
>>> If you want to get any performance gain from animated artists +
draw_artist
>>> you will need to use blitting (which will work with the OSX backend in
2.0).
>>
>> Yup, the real code does use blitting, but thanks for the reminder,
>
> Again - sorry to persist - but I'd be really grateful for any advice,

Sorry - again again - but can I nose this one up towards the surface?

Cheers,

Matthew

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-devel/attachments/20170401/6716df0c/attachment.html>