2954 removal of log kwarg from bar?

Hey Eric, I'm CC-ing the devel list because some of this has
potentially far reaching consequences.

    > In connection with the colorbar sizing problem I have been
    > thinking about adding a function list to axes, with the
    > functions to be executed early in the draw() method, to
    > handle this sort of thing. Using this mechanism to handle

I think this is a very nice idea -- I saw a talk at pycon one year about
the utility of adding hooks, eg before_somefunc_hook and after_somefunc_hook
that are customizable *for every function in your API*. The questions are

  1) what is the right data structure -- a single callable, a
     sequence, or a dictionary registry with connect/disconnect
     semantics (eg the backend event callback handler)

  2) what is the signature (see below)

  3) which artists should support it

Most elegant, but most expensive, is something like a ordered
dictionary which is supported for every artist. By renaming all the
artist draw methods _draw, we can do this quite simply in
backend_bases.Renderer with

def draw(self, renderer):
    for func in self.before_draw_hook.ordered_values():
        func(self, renderer)

    self._draw(renderer)

    for func in self.after_draw_hook.ordered_values():
        func(self, renderer)

I think this could be really useful and would help handle problems
that crop up all the time -- how to handle physical layout problems
where we need the renderer to get size information like you are
experiencing with colorbar. This problem also crops up in a lot of
text layout problems. Unfortunately, draw time layout creates other
problems (sometimes users want this info at the API level), and order
effects becomes very important and potentially complicated. But that
said, given the current architecture, something like this would be a
definite improvement.

I'm inclined to use an ordered dictionary because one wants the
connect/disconnect semantics that keys make easy, and because ordering
matters. There is a python cookbook recipe for an ordered dictionary,
and we could easily roll our own. Because the calls are potentially
expensive, we might want an optimization like

class MyOrderedDictionary:
    def __init__(blah):
        self.isempty = True

so we can do

def draw(renderer):
    if not self.before_draw_hook.isempty:
        for func in self.before_draw_hook.ordered_values():
            func(self, renderer)

    self._draw(renderer)

    if not self.after_draw_hook.isempty:
        for func in self.after_draw_hook.ordered_values():
            func(self, renderer)

Since 99% of the time I guess these will be empty and then we are just
adding a few attribute lookups and a boolean check for each draw.

JDH

John Hunter wrote:

Hey Eric, I'm CC-ing the devel list because some of this has
potentially far reaching consequences.

    > In connection with the colorbar sizing problem I have been
    > thinking about adding a function list to axes, with the
    > functions to be executed early in the draw() method, to
    > handle this sort of thing. Using this mechanism to handle

I think this is a very nice idea -- I saw a talk at pycon one year about
the utility of adding hooks, eg before_somefunc_hook and after_somefunc_hook
that are customizable *for every function in your API*. The questions are

  1) what is the right data structure -- a single callable, a
     sequence, or a dictionary registry with connect/disconnect
     semantics (eg the backend event callback handler)

  2) what is the signature (see below)

  3) which artists should support it

Most elegant, but most expensive, is something like a ordered
dictionary which is supported for every artist. By renaming all the
artist draw methods _draw, we can do this quite simply in
backend_bases.Renderer with

def draw(self, renderer):
    for func in self.before_draw_hook.ordered_values():
        func(self, renderer)

    self._draw(renderer)

    for func in self.after_draw_hook.ordered_values():
        func(self, renderer)

Nice, simple, elegant, but it doesn't quite match what I had in mind for axes. I was thinking that the place to put the hook call is inside the draw() method, so it can take advantage of the intial work done there: getting a cached renderer, checking for visibility. Maybe this doesn't matter.

Also, looking at backend_bases, I can't figure out where this goes. There is a RendererBase class, but it doesn't have a draw method. And there is a FigureCanvasBase, but its draw method is overridden by each backend. What am I missing?

I think this could be really useful and would help handle problems
that crop up all the time -- how to handle physical layout problems
where we need the renderer to get size information like you are
experiencing with colorbar. This problem also crops up in a lot of
text layout problems. Unfortunately, draw time layout creates other
problems (sometimes users want this info at the API level), and order
effects becomes very important and potentially complicated. But that
said, given the current architecture, something like this would be a
definite improvement.

I'm inclined to use an ordered dictionary because one wants the
connect/disconnect semantics that keys make easy, and because ordering
matters. There is a python cookbook recipe for an ordered dictionary,
and we could easily roll our own. Because the calls are potentially
expensive, we might want an optimization like

I agree, an ordered dictionary is ideal if one needs the option of multiple functions being executed. I would probably have it inherit from list and tack on the dictionary; I think this might make for the fastest cycling through the list, and that is the place where speed is needed.

class MyOrderedDictionary:
    def __init__(blah):
        self.isempty = True

so we can do

def draw(renderer):
    if not self.before_draw_hook.isempty:
        for func in self.before_draw_hook.ordered_values():
            func(self, renderer)

    self._draw(renderer)

    if not self.after_draw_hook.isempty:
        for func in self.after_draw_hook.ordered_values():
            func(self, renderer)

Since 99% of the time I guess these will be empty and then we are just
adding a few attribute lookups and a boolean check for each draw.

Detail:
Maybe it would be simpler and faster to initialize like this:

     self.before_draw_hook=None

and have
     def register_before_draw(self, name, func):
         if self.before_draw_hook is None:
             self.before_draw_hook = OrderedDictionary()
         self.before_draw_hook.append(name, func)

It saves one attribute lookup at draw time.

Larger picture:

Looking at the axes draw method, I am wondering whether a more general application of an OrderedDictionary (or ListDict, or whatever) wouldn't be a better approach. Why should there be before_draw_hook, draw, and after_draw_hook, with a big list generation and sorting operation at draw time? Could everything be done by having artists register all draw-time functions in a single ListDict, with sufficient ordering information to keep everything straight? That's pretty vague, and there is a lot I don't understand--but it just seems like there is an opportunity here for simplifying the overall structure with improved flexibility and no loss of speed. (Again, some kind of result-caching and need-for-recomputation-signalling would be needed.)

Eric