Home > Software design >  Get all artists of an axes matplotlib?
Get all artists of an axes matplotlib?

Time:04-24

I'm trying to animate a plot in mpl and I've decided the smartest way to do it is to add a number of axes dynamically using Gridspec. I provide a number of columns and rows that I want Gridspec to make Axes for on my canvas and then I can fill those axes with artists.

Since the number of axes is arbitrary and thus the number of artists is arbitrary, I thought it would work best to access the artists like so:

import matplotlib.pyplot as plt

fig = plt.figure(constrained_layout=False, figsize=(8,8), facecolor=bg_colour)
gs = fig.add_gridspec(nrows=nrows, ncols=ncols, hspace=0.1, wspace=0.1)

for i in range(nrows):
    for j in range(ncols):
        ax = plt.subplot(gs[i,j])

print(fig.axes[0].artists)

So the idea is that I can create all my axes dynamically and then I can also dynamically add artists to those axes by slicing fig.axes using the appropriate index. Once I have my axes selected I can just do

fig.axes[0].plot([],[])

to add an empty artist to the right axes, which I can then animate with the update function in my code.

The problem is that no matter how I set up the creation of the figure, the axes and the artists, the fig.axes[index].artists list is always empty. I don't understand how I can give the command to plot for my axes and then not have the artist show up in the list of all artists. Is .artists not actually the container for all artists that I need to use? Is the thing I'm looking for stored somewhere else? Does mpl not actually allow for this kind of thing in the first place?

Full code

import numpy as np
import itertools
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from matplotlib.ticker import AutoMinorLocator, MaxNLocator




def circle_points_x(period):

    t = np.linspace(0,2*np.pi,500)
    x = np.cos(period*t  np.pi/2)

    return x

def circle_points_y(period):

    t = np.linspace(0,2*np.pi,500)
    y = np.sin(period*t  np.pi/2)

    return y


# true distribution
ncols,nrows = (5,5)

bg_colour = np.array((84, 153, 215))/256
bg_colour = np.append(bg_colour,0.5)

fig = plt.figure(constrained_layout=False, figsize=(8,8), facecolor=bg_colour)

gs = fig.add_gridspec(nrows=nrows, ncols=ncols, hspace=0.1, wspace=0.1)


for i in range(nrows):
    for j in range(ncols):
        ax = plt.subplot(gs[i,j])
        ax.axis('off')


def init():

    for i in range(nrows):
        for j in range(ncols):
            x = circle_points_x(j 1)
            y = circle_points_y(i 1)

            fig.axes[i*nrows  j].plot(x,y,lw=0.5,aa=True)
            fig.axes[i*nrows  j].scatter([x[0]],[y[0]])


    print(fig.axes[0].artists)

    return list(itertools.chain(*[i.artists for i in fig.axes]))


def update(frame):

    for i in range(nrows):
        for j in range(ncols):
            # fig.axes[i*nrows  j].artists[0] # TURN THIS ON TO SEE THE ERROR
            pass
    return list(itertools.chain(*[i.artists for i in fig.axes]))




ani = FuncAnimation(fig, update, frames=range(1,8),repeat=False,init_func=init, blit=True,interval=40)
# ani.save('histogram.gif', dpi=300 ,writer="ffmpeg")
plt.show()

CodePudding user response:

Maybe what you are looking for is ax.get_children(), however it returns everything (lines, line collections, spines, legends maybe...), so you would have to filter the results somehow.

If you know in advance what kind of data you are plotting, here are a few location where Matplotlib separates the artists.

  • ax.lines stores the lines created with ax.plot.
  • ax.collections stores the collections (line collections, poly collections) created with ax.add_collection, ax.plot_surface, ax.contour, ax.contourf, ...
  • ax.images store the artists created with ax.imshow.
  • ax.patches contains artists created with ax.bar, ax.fill, ....
  • ax.tables contains artists created with ax.table.
  • Related