Related
Goal: Run example code and run example with and without minor ticks.
Plotly documentation has example code of a graph with minor ticks. Running the code fails.
import plotly.express as px
import pandas as pd
df = px.data.tips()
fig = px.scatter(df, x="total_bill", y="tip", color="sex")
fig.update_xaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True))
fig.update_yaxes(minor_ticks="inside")
fig.show()
Source - "Adding minor ticks"
Error:
(linechart) daniel#ubuntu-pcs:~/PycharmProjects/linechart$ python linechart/del.py
Traceback (most recent call last):
File "/home/daniel/PycharmProjects/linechart/linechart/del.py", line 8, in <module>
fig.update_xaxes(minor=dict(ticklen=6, tickcolor="black", showgrid=True))
File "/home/daniel/miniconda3/envs/linechart/lib/python3.9/site-packages/plotly/graph_objs/_figure.py", line 20166, in update_xaxes
obj.update(patch, overwrite=overwrite, **kwargs)
File "/home/daniel/miniconda3/envs/linechart/lib/python3.9/site-packages/plotly/basedatatypes.py", line 5082, in update
BaseFigure._perform_update(self, kwargs, overwrite=overwrite)
File "/home/daniel/miniconda3/envs/linechart/lib/python3.9/site-packages/plotly/basedatatypes.py", line 3877, in _perform_update
raise err
ValueError: Invalid property specified for object of type plotly.graph_objs.layout.XAxis: 'minor'
Did you mean "mirror"?
...
Bad property path:
minor
^^^^^
Remove all minor ticks:
fig.update_xaxes(dtick=1)
fig.update_yaxes(dtick=1)
However, this doesn't solve the documentation's code snippet.
In matplotlib, the update_from method of a Line2D object can be used to copy properties from another line (see e.g. this answer). This is not working if the two lines live on different axes. The following code:
fig, (ax1, ax2) = plt.subplots(2, 1)
line1, = ax1.plot(range(10), "r.")
line2, = ax2.plot(*line1.get_xydata().T)
line2.update_from(line1)
raises
AttributeError: 'NoneType' object has no attribute 'extents'
while the traceback leaves me puzzled.
My questions are:
Why is this error raised?
How can I copy (all) Line2D properties of line1 to line2 instead?
EDIT
After a bit more testing I can say that the AttributeError above is for example raised in a Jupyter notebook session with the %matplotlib inline backend. With the %matplotlib notebook backend or in a regular Python script (e.g. with the "qt5agg" backend), the code passes without an error but line2 is "invisible" afterwards.
For completeness, the above image was created using (Anaconda) Python 3.7.9 and matplotlib 3.3.1 with:
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.use("qt5agg")
fig, (ax1, ax2) = plt.subplots(2, 1)
line1, = ax1.plot(range(10), "r.")
line2, = ax2.plot(*line1.get_xydata().T)
line2.update_from(line1)
plt.savefig("test.png")
The problem remains that I cannot copy the Line2D properties from line1 to line2.
EDIT 2
Throwing a plt.tight_layout() into the mix brings back the AttributeError.
EDIT 3
As requested in the comments, here is the traceback for the error I get with plt.tight_layout() (EDIT 2):
Traceback (most recent call last):
File "test.py", line 11, in <module>
plt.tight_layout()
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/cbook/deprecation.py", line 451, in wrapper
return func(*args, **kwargs)
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/pyplot.py", line 1490, in tight_layout
gcf().tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/figure.py", line 2615, in tight_layout
pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/tight_layout.py", line 308, in get_tight_layout_figure
pad=pad, h_pad=h_pad, w_pad=w_pad)
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/tight_layout.py", line 84, in auto_adjust_subplotpars
bb += [ax.get_tightbbox(renderer, for_layout_only=True)]
File "/home/janjoswig/.pyenv/versions/miniconda3-4.7.12/envs/md379/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 4199, in get_tightbbox
if np.all(clip_extent.extents == axbbox.extents):
AttributeError: 'NoneType' object has no attribute 'extents'
It seems update_from updates too much, including the transformation and the clipbox. Maybe the error comes from the object being totally invisible after clipping to the wrong clipbox?
A workaround can be to save both before updating and setting them back:
from matplotlib import pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1)
line1, = ax1.plot(range(10), "r.")
line2, = ax2.plot(*line1.get_xydata().T)
old_transform = line2.get_transform()
old_clipbox = line2.clipbox
line2.update_from(line1)
line2.set_transform(old_transform)
line2.clipbox = old_clipbox
plt.tight_layout()
plt.draw()
I am very new to Python. I am trying to run this script:
https://scikit-image.org/docs/0.12.x/auto_examples/segmentation/plot_local_otsu.html
But, I'm getting this error:
Traceback (most recent call last):
File "/Users/janine/Downloads/plot_local_otsu.py", line 37, in <module>
fig, ax = plt.subplots(2, 2, figsize=(8, 5), sharex=True, sharey=True,
File "/usr/local/lib/python3.9/site-packages/matplotlib/_api/deprecation.py", line 471, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/matplotlib/pyplot.py", line 1440, in subplots
axs = fig.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey,
File "/usr/local/lib/python3.9/site-packages/matplotlib/_api/deprecation.py", line 471, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/matplotlib/figure.py", line 908, in subplots
axs = gs.subplots(sharex=sharex, sharey=sharey, squeeze=squeeze,
File "/usr/local/lib/python3.9/site-packages/matplotlib/gridspec.py", line 307, in subplots
axarr[row, col] = figure.add_subplot(
File "/usr/local/lib/python3.9/site-packages/matplotlib/figure.py", line 781, in add_subplot
ax = subplot_class_factory(projection_class)(self, *args, **pkw)
File "/usr/local/lib/python3.9/site-packages/matplotlib/axes/_subplots.py", line 36, in __init__
self._axes_class.__init__(self, fig, [0, 0, 1, 1], **kwargs)
File "/usr/local/lib/python3.9/site-packages/matplotlib/_api/deprecation.py", line 471, in wrapper
return func(*args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 648, in __init__
self.update(kwargs)
File "/usr/local/lib/python3.9/site-packages/matplotlib/artist.py", line 1064, in update
ret.append(func(v))
File "/usr/local/lib/python3.9/site-packages/matplotlib/axes/_base.py", line 1531, in set_adjustable
_api.check_in_list(["box", "datalim"], adjustable=adjustable)
File "/usr/local/lib/python3.9/site-packages/matplotlib/_api/__init__.py", line 126, in check_in_list
raise ValueError(
ValueError: 'box-forced' is not a valid value for adjustable; supported values are 'box', 'datalim'
I have installed scikit-image exactly as recommended here:
https://scikit-image.org/docs/stable/install.html.
I am on macOS Mojave.
As you can see from the link, the example is from the outdated 0.12.x version(s) of skimage, whereas 0.18.0 is current stable version. And, as the error message indicates, the error comes from this line:
fig, ax = plt.subplots(2, 2, figsize=(8, 5), sharex=True, sharey=True,
subplot_kw={'adjustable': 'box-forced'})
Obviously, the handling of the adjustable member has changed in matplotlib.pyplot over the years. By simply removing the subplot_kw parameter at all, for example, the code runs perfectly fine:
fig, ax = plt.subplots(2, 2, figsize=(8, 5), sharex=True, sharey=True)
In fact, that's also, what the updated example from the skimage documentation looks like (second example there). Notice: You'll have to add two import statements on your own, since the given code there in incomplete.
I am trying to save a simple matplotlib animation from Jake Vanderplas, but I keep getting OSError: [Errno 13] Permission denied.
I should note that I made two small modifications to Jake Vanderplas's example. I installed ffmpeg from MacPorts so I added the line plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin' and I ran into the problem discussed in (Using FFmpeg and IPython), so I added FFwriter = animation.FFMpegWriter().
Here is the code:
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin'
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=200, interval=20, blit=True)
FFwriter = animation.FFMpegWriter()
anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])
Here is the traceback:
File "ani_debug.py", line 34, in <module>
anim.save('basic_animation.mp4', writer = FFwriter, fps=30, extra_args=['-vcodec', 'libx264'])
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site- packages/matplotlib/animation.py", line 712, in save
with writer.saving(self._fig, filename, dpi):
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/contextlib.py", line 17, in __enter__
return self.gen.next()
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 169, in saving
self.setup(*args)
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 159, in setup
self._run()
File "/Users/Ben/Library/Enthought/Canopy_64bit/User/lib/python2.7/site-packages/matplotlib/animation.py", line 186, in _run
stdin=subprocess.PIPE)
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 709, in __init__
errread, errwrite)
File "/Applications/Canopy.app/appdata/canopy-1.3.0.1715.macosx-x86_64/Canopy.app/Contents/lib/python2.7/subprocess.py", line 1326, in _execute_child
raise child_exception
OSError: [Errno 13] Permission denied
I have also tried using Spyder's built-in python and received a similar traceback. Any suggestions?
EDIT: I realized that I did not give the proper path to ffmpeg. Apparently, plt.rcParams['animation.ffmpeg_path'] does not work similar to PYTHONPATH. You must tell the animation module exactly where ffmpeg is with plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'.
Now, I get a movie file that will play, but the content is completely garbled. I can't tell what I am looking at.
Here is the traceback:
Exception in Tkinter callback
Traceback (most recent call last):
File "Tkinter.pyc", line 1470, in __call__
File "Tkinter.pyc", line 531, in callit
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backends/backend_tkagg.py", line 141, in _on_timer
TimerBase._on_timer(self)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/backend_bases.py", line 1203, in _on_timer
ret = func(*args, **kwargs)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 876, in _step
still_going = Animation._step(self, *args)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 735, in _step
self._draw_next_frame(framedata, self._blit)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 753, in _draw_next_frame
self._pre_draw(framedata, blit)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 766, in _pre_draw
self._blit_clear(self._drawn_artists, self._blit_cache)
File "/Applications/Spyder.app/Contents/Resources/lib/python2.7/matplotlib/animation.py", line 806, in _blit_clear
a.figure.canvas.restore_region(bg_cache[a])
KeyError: <matplotlib.axes.AxesSubplot object at 0x104cfb150>
EDIT:
For some reason, everything is working fine now. I have tried things on my home computer and my work computer, and neither one can recreate the garbled video file I got after I fixed the ffmpeg path issue.
EDIT:
Aaaahaaa! I tracked this sucker down. Sometimes I would import a module that had plt.rcParams['savefig.bbox'] = 'tight' in it. (I would never use that module, but rcParams persist, until you restart your python interpreter.) That setting causes the video to come out all garbled. I will post my solution below.
So it turns out there were two issues.
Issue #1: The path to ffmpeg was wrong. I thought I needed to provide the path to the directory that ffmpeg resides in, but I needed to provide the path all the way to the ffmpeg binary.
Issue #2: Prior to testing out my code to generate videos, I sometimes would import a module with the setting plt.rcParams['savefig.bbox'] = 'tight'. (I did not think much of it, because I did not use the module, but rcParams persist until you restart the python interpreter.) This plt.rcParams['savefig.bbox'] = 'tight' causes the video file to save without any errors, but the frames are all garbled when you try to play the video. Although it took me all evening to track this down, it turns out this is a known issue.
Here is the updated solution that creates a video file for me with a nice, translating, sine wave.
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = '/opt/local/bin/ffmpeg'
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
FFwriter = animation.FFMpegWriter(fps=30, extra_args=['-vcodec', 'libx264'])
anim.save('basic_animation.mp4', writer=FFwriter)
Thank you Stretch for your valuable answer. I found that mentioning extra args inside anim.save() results in error. Hence the code is updated as shown below,
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
plt.rcParams['animation.ffmpeg_path'] = r'I:\FFmpeg\bin\ffmpeg' #make sure you download FFmpeg files for windows 10 from https://ffmpeg.zeranoe.com/builds/
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))
line, = ax.plot([], [], lw=2)
def init():
line.set_data([], [])
return line,
def animate(i):
x = np.linspace(0, 2, 1000)
y = np.sin(2 * np.pi * (x - 0.01 * i))
line.set_data(x, y)
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=200, interval=20, blit=True)
FFwriter=animation.FFMpegWriter(fps=30, extra_args=['-vcodec', 'libx264'])
anim.save(r'I:\Understanding_objective functions\test\basic_animation.mp4', writer=FFwriter)
plt.show()
Hope this might helps someone trying to save animation plots to .mp4 format.
Further to Stretch's answer, I found that some of the parameters being passed to anim.save() do not appear to achieve the desired effect. Specifically fps was 5 (default) and not the 30 being set. By passing fps=30 to animation.FFMpegWriter it does work.
So:
FFwriter = animation.FFMpegWriter(fps=30)
anim.save('basic_animation.mp4', writer=FFwriter, extra_args=['-vcodec', 'libx264'])
Note that the video is now 7 seconds long (200 frames # 30 fps) rather than 40 seconds (200 frames # 5 fps). Note also that a default of 5 fps corresponds to the default 200 ms/frame interval in FuncAnimation, and strictly speaking the 20 ms animation interval used here corresponds to 50 fps.
For those struggling to achieve better video quality, it is also possible to pass a bitrate (integer in kbps) to animation.FFMpegWriter, eg:
FFwriter = animation.FFMpegWriter(fps=30, bitrate=2000)
I tried various extra_args in an effort to achieve better quality, without much success.
I had garbling issues when I first (naively) tried to modify the working
example of Stretch's answer to show the graph in realtime (as well as keep the movie).
Not quite right mods of Stretch's answer (which worked for me)
plt.ion() interaction on
plt.draw() and plt.show() inside animate function, before return statent
frames=20, interval=200 to slow graph creation a bit, but still make a 4 second movie
Now plot shows up in a window as it is being created,
but the output movie is garbled.
Correct step 2:
2a: plt.draw() inside animate function
2b: plt.show() just after the animate function
Now movie plays back ungarbled.
I have a fairly simple plotting routine that looks like this:
from __future__ import division
import datetime
import matplotlib
matplotlib.use('Agg')
from matplotlib.pyplot import figure, plot, show, legend, close, savefig, rcParams
import numpy
from globalconstants import *
def plotColumns(columnNumbers, t, out, showFig=False, filenamePrefix=None, saveFig=True, saveThumb=True):
lineProps = ['b', 'r', 'g', 'c', 'm', 'y', 'k', 'b--', 'r--', 'g--', 'c--', 'm--', 'y--', 'k--', 'g--', 'b.-', 'r.-', 'g.-', 'c.-', 'm.-', 'y.-', 'k.-']
rcParams['figure.figsize'] = (13,11)
for i in columnNumbers:
plot(t, out[:,i], lineProps[i])
legendStrings = list(numpy.zeros(NUMCOMPONENTS))
legendStrings[GLUCOSE] = 'GLUCOSE'
legendStrings[CELLULOSE] = 'CELLULOSE'
legendStrings[STARCH] = 'STARCH'
legendStrings[ACETATE] = 'ACETATE'
legendStrings[BUTYRATE] = 'BUTYRATE'
legendStrings[SUCCINATE] = 'SUCCINATE'
legendStrings[HYDROGEN] = 'HYDROGEN'
legendStrings[PROPIONATE] = 'PROPIONATE'
legendStrings[METHANE] = "METHANE"
legendStrings[RUMINOCOCCUS] = 'RUMINOCOCCUS'
legendStrings[METHANOBACTERIUM] = "METHANOBACTERIUM"
legendStrings[BACTEROIDES] = 'BACTEROIDES'
legendStrings[SELENOMONAS] = 'SELENOMONAS'
legendStrings[CLOSTRIDIUM] = 'CLOSTRIDIUM'
legendStrings = [legendStrings[i] for i in columnNumbers]
legend(legendStrings, loc='best')
dt = datetime.datetime.now()
dtAsString = dt.strftime('%d-%m-%Y_%H-%M-%S')
if filenamePrefix is None:
filenamePrefix = ''
if filenamePrefix != '' and filenamePrefix[-1] != '_':
filenamePrefix += '_'
if saveFig:
savefig(filenamePrefix+dtAsString+'.eps')
if saveThumb:
savefig(filenamePrefix+dtAsString+'.png', dpi=300)
if showFig: f.show()
close('all')
When I plot this in single iterations, it works fine. However, the moment I put it in a loop, matplotlib throws a hissy fit...
Traceback (most recent call last):
File "c4hm_param_variation_h2_conc.py", line 148, in <module>
plotColumns(columnNumbers, timeVector, out, showFig=False, filenamePrefix='c
4hm_param_variation_h2_conc_'+str(hydrogen_conc), saveFig=False, saveThumb=True)
File "D:\phdproject\alexander paper\python\v3\plotcolumns.py", line 48, in plo
tColumns
savefig(filenamePrefix+dtAsString+'.png', dpi=300)
File "C:\Python25\lib\site-packages\matplotlib\pyplot.py", line 356, in savefi
g
return fig.savefig(*args, **kwargs)
File "C:\Python25\lib\site-packages\matplotlib\figure.py", line 1032, in savef
ig
self.canvas.print_figure(*args, **kwargs)
File "C:\Python25\lib\site-packages\matplotlib\backend_bases.py", line 1476, i
n print_figure
**kwargs)
File "C:\Python25\lib\site-packages\matplotlib\backends\backend_agg.py", line
358, in print_png
FigureCanvasAgg.draw(self)
File "C:\Python25\lib\site-packages\matplotlib\backends\backend_agg.py", line
314, in draw
self.figure.draw(self.renderer)
File "C:\Python25\lib\site-packages\matplotlib\artist.py", line 46, in draw_wr
apper
draw(artist, renderer, *kl)
File "C:\Python25\lib\site-packages\matplotlib\figure.py", line 773, in draw
for a in self.axes: a.draw(renderer)
File "C:\Python25\lib\site-packages\matplotlib\artist.py", line 46, in draw_wr
apper
draw(artist, renderer, *kl)
File "C:\Python25\lib\site-packages\matplotlib\axes.py", line 1735, in draw
a.draw(renderer)
File "C:\Python25\lib\site-packages\matplotlib\artist.py", line 46, in draw_wr
apper
draw(artist, renderer, *kl)
File "C:\Python25\lib\site-packages\matplotlib\legend.py", line 374, in draw
bbox = self._legend_box.get_window_extent(renderer)
File "C:\Python25\lib\site-packages\matplotlib\offsetbox.py", line 209, in get
_window_extent
px, py = self.get_offset(w, h, xd, yd)
File "C:\Python25\lib\site-packages\matplotlib\offsetbox.py", line 162, in get
_offset
return self._offset(width, height, xdescent, ydescent)
File "C:\Python25\lib\site-packages\matplotlib\legend.py", line 360, in findof
fset
return _findoffset(width, height, xdescent, ydescent, renderer)
File "C:\Python25\lib\site-packages\matplotlib\legend.py", line 325, in _findo
ffset_best
ox, oy = self._find_best_position(width, height, renderer)
File "C:\Python25\lib\site-packages\matplotlib\legend.py", line 817, in _find_
best_position
verts, bboxes, lines = self._auto_legend_data()
File "C:\Python25\lib\site-packages\matplotlib\legend.py", line 669, in _auto_
legend_data
tpath = trans.transform_path(path)
File "C:\Python25\lib\site-packages\matplotlib\transforms.py", line 1911, in t
ransform_path
self._a.transform_path(path))
File "C:\Python25\lib\site-packages\matplotlib\transforms.py", line 1122, in t
ransform_path
return Path(self.transform(path.vertices), path.codes,
File "C:\Python25\lib\site-packages\matplotlib\transforms.py", line 1402, in t
ransform
return affine_transform(points, mtx)
MemoryError: Could not allocate memory for path
This happens on iteration 2 (counting from 1), if that makes a difference. The code is running on Windows XP 32-bit with python 2.5 and matplotlib 0.99.1, numpy 1.3.0 and scipy 0.7.1.
EDIT: The code has now been updated to reflect the fact that the crash actually occurs at the call to legend(). Commenting that call out solves the problem, though obviously, I would still like to be able to put a legend on my graphs...
Is each loop supposed to generate a new figure? I don't see you closing it or creating a new figure instance from loop to loop.
This call will clear the current figure after you save it at the end of the loop:
pyplot.clf()
I'd refactor, though, and make your code more OO and create a new figure instance on each loop:
from matplotlib import pyplot
while True:
fig = pyplot.figure()
ax = fig.add_subplot(111)
ax.plot(x,y)
ax.legend(legendStrings, loc = 'best')
fig.savefig('himom.png')
# etc....
I've also run into this error. what seems to have fixed it is
while True:
fig = pyplot.figure()
ax = fig.add_subplot(111)
ax.plot(x,y)
ax.legend(legendStrings, loc = 'best')
fig.savefig('himom.png')
#new bit here
pylab.close(fig) #where f is the figure
running my loop stably now with fluctuating memory but no consistant increase
Answer from ninjasmith worked for me too - pyplot.close() enabled my loops to work.
From the pyplot tutorial, Working with multiple figures and axes:
You can clear the current figure with clf() and the current
axes with cla(). If you find this statefulness, annoying, don’t
despair, this is just a thin stateful wrapper around an object
oriented API, which you can use instead (see Artist tutorial)
If you are making a long sequence of figures, you need to be aware of
one more thing: the memory required for a figure is not completely
released until the figure is explicitly closed with close(). Deleting
all references to the figure, and/or using the window manager to kill
the window in which the figure appears on the screen, is not enough,
because pyplot maintains internal references until close() is called.
In my case, matplotlib version 3.5.0, As Hui Liu san says,
Following method can keep memory usage low
import matplotlib
print(matplotlib.__version__) #'3.5.0'
import matplotlib.pyplot as plt
plt.savefig('your.png')
# Add both in this order for keeping memory usage low
plt.clf()
plt.close()
I had a similar issue when I was using it from jupyter, putting plt.clf() and plt.close() in the loop did not work.
But this helped:
import matplotlib
matplotlib.use('Agg')
This disables interactive backend for matplotlib.