Search code examples
pythonmatplotlibvalueerror

Adding patches to axes in loop returns a ValueError


So, I have a for loop that plots creatures in a figure's subplots. I'm using this for subplot arrangement. Here is my code excerpt:

import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib.collections import PatchCollection
import numpy as np
from grid_strategy import strategies
from shapely.geometry import MultiLineString
from descartes.patch import PolygonPatch


fig = plt.figure()
space = [
    Circle((2, 2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
    Circle((-2, 2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
    Circle((2, -2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
]

lines = [
    [
        [0.0, 0.0],
        [0.007963267107332634, 9.999996829318349],
        [-9.992024050168064, 10.015923358483217]
    ],
    [
        [-9.992024050168064, 10.015923358483217],
        [-5.547622120022902, 3.3640595983538804],
        [-2.7450196155284288, 10.857084301489543]
    ],
    [
        [-2.7450196155284288, 10.857084301489543],
        [-8.83003187757613, 8.873999388852386]
    ],
    [
        [-2.7450196155284288, 10.857084301489543],
        [-1.1168525035132877, 0.9905209760275202]
    ],
    [
        [-9.992024050168064, 10.015923358483217],
        [-4.576474350758081, 15.904201668245792],
        [-9.381605405732934, 9.508053175245003]
    ],
    [
        [-9.381605405732934, 9.508053175245003],
        [-9.348197751236784, 15.907965981574565]
    ],
    [
        [-9.381605405732934, 9.508053175245003],
        [-15.091199417814586, 1.2982702172611962]
    ]
]

creature = MultiLineString(lines)

creature_patch = PolygonPatch(creature.buffer(5))

plot_spec = strategies.SquareStrategy('center').get_grid(2)

for _, sub in zip(range(2), plot_spec):
    ax = fig.add_subplot(sub)

    for line in creature:
        x, y = line.xy
        ax.plot(x, y, 'r-')

    ax.add_patch(creature_patch)
    for p in space:
        ax.add_patch(p)

ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
ax.autoscale(axis='y')
ax.axis('equal')
plt.show()

For a single iteration of the for loop it works and outputs the following: Creature with patches

Where:
for line in creature: is the red lines
ax.add_patch(creature_patch) is the blue blob and
for p in space: is the red circles

However as soon as I want to plot multiple subfigures I get the following error:

  File "c:\Users\Zack\Google Drive\Studies\Meesters\Meesters\New Direction (L-Systems)\New-Direction-L-Systems-\Versions\tools\render.py", line 109, in genDraw
    ax.add_patch(p)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 1967, in add_patch
    self._set_artist_props(p)
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\axes\_base.py", line 926, in _set_artist_props
    a.axes = self
  File "C:\ProgramData\Anaconda3\lib\site-packages\matplotlib\artist.py", line 209, in axes
    raise ValueError("Can not reset the axes.  You are probably "
ValueError: Can not reset the axes.  You are probably trying to re-use an artist in more than one Axes which is not supported 

which i don't understand because the ax variable is set to a different Axes object at each iteration.

Thank you for any help


Solution

  • As commented already, space contains several patches. Once you have added them to one axes, you cannot add them to another axes. This is what the error tells you.

    The solution is to create one set of patches per axes, e.g.:

    import matplotlib.pyplot as plt
    from matplotlib.patches import Circle
    import numpy as np
    
    
    fig = plt.figure()
    
    def get_space():
        space = [
            Circle((2, 2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
            Circle((-2, 2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
            Circle((2, -2), radius=5, color='red',  alpha=np.random.uniform(0, 1)),
        ]
        return space
    
    
    plot_spec = fig.add_gridspec(1,2)
    
    for _, sub in zip(range(2), plot_spec):
        ax = fig.add_subplot(sub)
    
        for p in get_space():
            ax.add_patch(p)
    
        ax.get_xaxis().set_visible(False)
        ax.get_yaxis().set_visible(False)
        ax.autoscale(axis='y')
        ax.axis('equal')
    plt.show()