Izak Joubert
Izak Joubert

Reputation: 1001

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

Upvotes: 1

Views: 1564

Answers (1)

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339170

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()

Upvotes: 3

Related Questions