Matplotlib: using a figure object to initialize a plot

前端 未结 2 1286
后悔当初
后悔当初 2020-12-09 00:57

I am building a class of plot tools for a specific experiment. I currently have two plot methods, a static plot using imshow(), and a \"movie\" format also using imshow() .<

相关标签:
2条回答
  • 2020-12-09 01:05

    To show a plot you'll want to use fig.canvas.draw() where fig is an instance of the Figure class. fig.canvas.draw() is the API version of the interactive shell (read: pylab) function draw()

    If you need to get the Axes or Figure from an AxesImage object you can call either im.get_axes() or im.get_figure(), respectively.

    As far as writing "good" object-oriented code the user interface examples might be good place to start.

    0 讨论(0)
  • 2020-12-09 01:15

    You need to understand a bit of architecture of matplotlib first (see here for a long article by the founder and current lead developer). At the bottom of the backend layer which deals with rendering and talking to the hardware. On top of that layer are artists which know how to draw them selves by tell the backend object what to do. On top of that layer is the pyplot state machine interface which mimics MATLAB.

    Everything you see in a figure is represented internally as an Artist and artists can contain other artists. For example, the Axes object keeps track of it's children Artists which are the axes spines, tickes, labels, your lines or images etc and Axes objects are children of Figure objects. When you tell a figure to draw itself (via fig.canvas.draw()) all the children artists are drawn recursively.

    One draw back of this design is that a given instantiation of an Artist can be in exactly one figure (and moving them between figures is hard) so you can't make a AxesImage object and then keep reusing it.

    This design also separates what Artists know about. Axes objects know about things like tick location and labels and the display range (which it does by knowing about Axis object, but that is getting even more into the weeds). Things like vmin and vmax are encapsulated in Normalize (doc) objects which the AxesImage keeps track of. This means that you will need to separate how you deal with everything on your list.

    I would suggest either using a factory-like pattern here, or a curry-like pattern

    Factory-like:

    def set_up_axes(some, arguements):
        '''
        Factory to make configured axes (
        '''
        fig, ax = plt.subplots(1, 1) # or what ever layout you want
        ax.set_*(...)
        return fig, ax
    
    
    my_norm = matplotlib.colors.Normalize(vmin, mmax) # or write a factory to do fancier stuff
    fig, ax = set_up_axes(...)
    ax.imshow(..., norm=my_norm)
    fig2, ax2 = set_up_axes(...)
    ax2.imshow(..., norm=mynorm)
    

    You can wrap up a whole set of kwargs to easily re-use them as such:

    my_imshow_args = {'extent':[...],
                      'interpolation':'nearest',
                      'norm': my_norm,
                       ...}
    
    ax2.imshow(..., **my_imshow_args)
    

    Curry-like:

    def my_imshow(im, ax=None, *args, **kwargs):
        if ax is None:
            ax = plt.gca()
        # do all of your axes set up
        ax.set_xlim(..)
    
        # set default vmin and vmax
        # you can drop some of these conditionals if you don't want to be
        # able to explicitly override the defaults
        if 'norm' not in kwargs:
            vmin = kwargs.pop('vmin', None)
            vmax = kwargs.pop('vmax', None)
            if vmin is None:
                vmin = default_vmin # or what ever
            if vmax is None:
                vmax = default_vmax
            my_norm = matplotlib.colors.Normalize(vmin, mmax)
            kwargs['norm'] = norm
    
        # add a similar block for `extent` 
        # or any other kwargs you want to change the default of
    
        ax.figure.canvas.draw() # if you want to force a re-draw
        return ax.imshow(im, *args, **kwargs)
    

    If you want to be super clever, you can monkey-patch plt.imshow with your version

    plt.imshow = my_imshow
    

    There is also the rcParams interface which will allow you to change the default values of many bits and pieces of matplotlib in a global way.

    And yet another way to accomplish this (through partial)

    0 讨论(0)
提交回复
热议问题