Hello. In order to produce an animation frame by frame, I’m looking for a way to flush or close the Plotter()
object at the end of each loop.
from compas_plotters import Plotter
from compas.geometry import Point
from random import randint
l = [(randint(0, 10),randint(0, 10)) for _ in range(30)]
for p in l:
plotter = Plotter()
plotter.add(Point(*p)) # minimal example
plotter.save("./frames/{:02d}_{:02d}.png".format(*p))
# close/flush plotter
The above example code produces the warning : RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (
matplotlib.pyplot.figure) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam
figure.max_open_warning). figure = plt.figure(
Thanks !
Maybe the solution could be here : matplotlib.figure — Matplotlib 3.5.3 documentation
I extend the example for a use case with layers.
from compas_plotters import Plotter
from compas.geometry import Point
from random import randint
l = [(randint(0, 10),randint(0, 10)) for _ in range(30)]
l2 = [(randint(0, 10),randint(0, 10)) for _ in range(30)]
for p, p2 in zip(l, l2):
plotter = Plotter()
plotter.add(Point(*p)) # minimal example
plotter.zoom_extents()
plotter.save("./frames/{:02d}_{:02d}_Layer_1.svg".format(*p)) # --> first layer
# --> clear plotter
plotter.add(Point(*p2)) # minimal example
plotter.save("./frames/{:02d}_{:02d}_Layer_2.svg".format(*p)) # --> second layer
In this example it is guaranteed that layer 1 and layer 2 are of the same size. Matplotlib seems to optimize image size and to make new plotter objects could therefore end up with two layers of different sizes.
UPDATE:
Gettng closer to the goal. When adding geometry, the Plotter instance creates an internal Artist object. It could normally be accessed and cleared. Though it seems not implemented yet.
for arts in plotter.artists:
arts.clear()
Having some trouble understanding the error message.
raise PluginNotInstalledError('Plugin not found for extension point URL: {}'.format(extension_point_url)) compas.plugins.PluginNotInstalledError: Plugin not found for extension point URL: https:/plugins.compas.dev/drawing-utils/clear
I guess a starting point is here: compas/artist.py at main · compas-dev/compas · GitHub
the plotter provides a decorator method for making animated gifs. it is however, not very well documented. therefore please refer to the following example (which generates one of the images of the plotter tutorial in the docs: dynamic plots)
from compas.geometry import Pointcloud, Translation
from compas.utilities import i_to_red, pairwise
from compas_plotters import Plotter
plotter = Plotter(figsize=(8, 5))
pointcloud = Pointcloud.from_bounds(8, 5, 0, 10)
for index, (a, b) in enumerate(pairwise(pointcloud)):
color = i_to_red(max(index / 10, 0.1), normalize=True)
artist = plotter.add(a, edgecolor=color)
plotter.add(b, size=10, edgecolor=(1, 0, 0))
plotter.zoom_extents()
plotter.pause(1.0)
@plotter.on(
interval=0.1,
frames=50,
record=True,
recording="docs/_images/tutorial/plotters_dynamic.gif",
dpi=150,
)
def move(frame):
print(frame)
for a, b in pairwise(pointcloud):
vector = b - a
a.transform(Translation.from_vector(vector * 0.1))
plotter.show()
1 Like
Another example coming up. This pattern adds objects to the animation (instead transforming an existing one). The important thing to note is that the number of frames has to be defined beforehand:
from random import randint
from compas.geometry import Point
from compas_plotters import Plotter
plot = Plotter(view=((-8.0, 16.0), (-5.0, 10.0)),
figsize=(8.0, 5.0),
dpi=100, bgcolor=(1.0, 1.0, 1.0),
show_axes=False,
zstack='zorder')
random_points = [Point(randint(0, 10), randint(0, 10))
for _ in range(randint(0, 30))]
def animate(plotter, objects, file):
@plotter.on(interval=0.1,
frames=len(objects),
record=True,
recording=file)
def add_objects(frame):
plotter.add(objects[frame], size=10)
animate(plot, random_points, "./demo.gif")
print("animation completed")
plot.show()
But it’s not possible to invoke a second function for a same gif file. The file is overwritten.