I’ve just been reviewing a really useful PR (https://github.com/matplotlib/matplotlib/pull/1531) from Pierre Haessig which speeds up the drawing of non-visible artists by bringing the following line to the top of the LineArtist’s draw method:
if self.get_visible() is False:
return
This does fix the problem (and will fix the problem for all other artists if applied in the same way), but it relies on a developer remembering the rule of thumb that they must always start their draw method with these two (simple) lines. Additionally, testing this functionality is actually quite hard without resorting to timing the execution.
It made we wonder if there was a better approach to fixing this. Having a decorator to do this for you is a good idea, except that a developer would need to remember to decorate their subclass’ draw method, so the next level up is to use a metaclass to always wrap the draw method with the “if visible” lines.
An example of implementing this (apologies if the code doesn’t come out well in the email):
class ArtistMeta(type):
def new(cls, classname, bases, class_dict):
# replace the draw method with one which short-circuits if self.visible is False
draw_method = class_dict[‘draw’]
def draw(self, *args, **kwargs):
if self.visible is False:
print ‘draw not called with visible={}’.format(self.visible)
return
else:
return draw_method(self, *args, **kwargs)
class_dict[‘draw’] = draw
return type.__new__(cls, classname, bases, class_dict)
class Artist(object):
metaclass = ArtistMeta
def __init__(self, visible=True):
self.visible = visible
def draw(self, renderer=None):
print 'draw called with visible={}'.format(self.visible)
return 'foobar'
class SubArtist(Artist):
def draw(self, renderer=None):
print “subclass’ draw method”
return Artist.draw(self, renderer=renderer)
With the following results:
a = Artist().draw(‘wibble’)
draw called with visible=True
b = Artist(False).draw(‘wibble’)
draw not called with visible=False
c = SubArtist(True).draw(‘wibble’)
subclass’ draw method
draw called with visible=True
d = SubArtist(False).draw(‘wibble’)
draw not called with visible=False
In my eyes this makes testing the functionality possible without timing (and is therefore an improvement), but I wanted to know how others felt about the approach, and in particular, using more metaclasses in matplotlib (a simple tutorial which I found useful: http://www.voidspace.org.uk/python/articles/metaclasses.shtml).
Cheers,
Phil