Prevent matplotlib statefulness

前端 未结 1 1739
星月不相逢
星月不相逢 2020-12-28 22:02

If I create an Axes object in matplotlib and mutate it (i.e. by plotting some data) and then I call a function without passing my Axes

相关标签:
1条回答
  • 2020-12-28 22:41

    Sure! What you need to do is bypass the pyplot state machine entirely when you make your figure.

    It's more verbose, as you can't just call fig = plt.figure().


    First off, let me explain how plt.gca() or plt.gcf() works. When using the pyplot interface, matplotlib stores all created-but-not-displayed figure managers. Figure managers are basically the gui wrapper for a figure.

    plt._pylab_helpers.Gcf is the singleton object that stores the figure managers and keeps track of which one is currently active. plt.gcf() returns the active figure from _pylab_helpers.Gcf. Each Figure object keeps track of it's own axes, so plt.gca() is just plt.gcf().gca().

    Normally, when you call plt.figure(), it:

    1. Creates the figure object that's returned
    2. Creates a FigureManager for that figure using the appropriate backend
    3. The figure manager creates a FigureCanvas, gui window (as needed), and NavigationToolbar2 (zoom buttons, etc)
    4. The figure manager instance is then added to _pylab_helpers.Gcf's list of figures.

    It's this last step that we want to bypass.


    Here's a quick example using a non-interactive backend. Note that because we're not worried about interacting with the plot, we can skip the entire figure manager and just create a Figure and FigureCanvas instance. (Technically we could skip the FigureCanvas, but it will be needed as soon as we want to save the plot to an image, etc.)

    import matplotlib.backends.backend_agg as backend
    from matplotlib.figure import Figure
    
    # The pylab figure manager will be bypassed in this instance. `plt.gca()`
    # can't access the axes created here.
    fig = Figure()
    canvas = backend.FigureCanvas(fig)
    ax = fig.add_subplot(111)
    

    Just to prove that gca can't see this axes:

    import matplotlib.pyplot as plt
    import matplotlib.backends.backend_agg as backend
    from matplotlib.figure import Figure
    
    # Independent figure/axes
    fig = Figure()
    canvas = backend.FigureCanvas(fig)
    ax = fig.add_subplot(111)
    ax.plot(range(10))
    
    # gca() is completely unaware of this axes and will create a new one instead:
    ax2 = plt.gca()
    print 'Same axes?:', id(ax) == id(ax2)
    
    # And `plt.show()` would show the blank axes of `ax2`
    

    With an interactive backed, it's a touch more complicated. You can't call plt.show(), so you need to start the gui's mainloop yourself. You can do it all "from scratch" (see any of the "embedding matplotlib" examples), but the FigureManager abstracts the backed-specific parts away:

    As an example using the TkAgg backend:

    import matplotlib.backends.backend_tkagg as backend
    from matplotlib.figure import Figure
    
    fig = Figure()
    ax = fig.add_subplot(111)
    
    manager = backend.new_figure_manager_given_figure(1, fig)
    manager.show()
    backend.show.mainloop()
    

    To use one of the other backends, just change the backend import. For example, for Qt4:

    import matplotlib.backends.backend_qt4agg as backend
    from matplotlib.figure import Figure
    
    fig = Figure()
    ax = fig.add_subplot(111)
    
    manager = backend.new_figure_manager_given_figure(1, fig)
    manager.show()
    backend.show.mainloop()
    

    This actually even works with the nbagg backend used in IPython notebooks. Just change the backend import to import matplotlib.backends.backend_nbagg as backend

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