I am trying to include a legend for my stackplot. I know that you cannot do it in the normal way so I followed the instructions from this similar post however there is still an error.
x=data[:,-1]
y1=map(int,data[:,1])
y2=map(int,data[:,2])
y3=map(int,data[:,3])
y4=map(int,data[:,4])
y5=map(int,data[:,5])
y6=map(int,data[:,6])
y7=map(int,data[:,7])
y8=map(int,data[:,8])
y9=map(int,data[:,9])
y10=map(int,data[:,0])
xnew=np.linspace(0,len(x),50)
smooth_y1=spline(np.arange(len(x)),y1,xnew)
smooth_y2=spline(np.arange(len(x)),y2,xnew)
smooth_y3=spline(np.arange(len(x)),y3,xnew)
smooth_y4=spline(np.arange(len(x)),y4,xnew)
smooth_y5=spline(np.arange(len(x)),y5,xnew)
smooth_y6=spline(np.arange(len(x)),y6,xnew)
smooth_y7=spline(np.arange(len(x)),y7,xnew)
smooth_y8=spline(np.arange(len(x)),y8,xnew)
smooth_y9=spline(np.arange(len(x)),y9,xnew)
smooth_y10=spline(np.arange(len(x)),y10,xnew)
plt.stackplot(np.arange(50),smooth_y1,smooth_y2,smooth_y3,smooth_y4,smooth_y5,smooth_y6,smooth_y7,smooth_y8,smooth_y9,smooth_y10)
plt.ylim([0,30])
plt.legend([smooth_y1,smooth_y2,smooth_y3,smooth_y4,smooth_y5,smooth_y6,smooth_y7,smooth_y8,smooth_y9,smooth_y10],['hfsdkjfhs','sldjfhsdkj','sdrtryf','sdfsd','sdkjf','sdfsd','sdrtdf','sfsd','sdaaafs','sdffghs'])
plt.show()
However an error occurs on the line with the legend. It says
File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 3381, in legend
ret = gca().legend(*args, **kwargs)
File "C:\Python27\lib\site-packages\matplotlib\axes.py", line 4778, in legend
self.legend_ = mlegend.Legend(self, handles, labels, **kwargs)
File "C:\Python27\lib\site-packages\matplotlib\legend.py", line 366, in __init__
self._init_legend_box(handles, labels)
File "C:\Python27\lib\site-packages\matplotlib\legend.py", line 606, in _init_legend_box
handler = self.get_legend_handler(legend_handler_map, orig_handle)
File "C:\Python27\lib\site-packages\matplotlib\legend.py", line 546, in get_legend_handler
if orig_handle in legend_handler_keys:
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Does anyone know how to solve this?
from matplotlib.patches import Rectangle
label_list = ['hfsdkjfhs','sldjfhsdkj','sdrtryf','sdfsd','sdkjf','sdfsd','sdrtdf','sfsd','sdaaafs','sdffghs']
x = data[:, -1]
xnew=np.linspace(0,len(x),50)
smoothed_data = [spline(np.arange(len(x)),data[:, j%10],xnew)
for j in range(1, 11)]
# get a figure and axes
fig, ax = plt.subplots()
# make the stack plot
stack_coll = ax.stackplot(xnew, smoothed_data)
# set the ylim
ax.set_ylim([0,30])
# make proxy artists
proxy_rects = [Rectangle((0, 0), 1, 1, fc=pc.get_facecolor()[0]) for pc in stack_coll]
# make the legend
ax.legend(proxy_rects, label_list)
# re-draw the canvas
plt.draw()
Related
I was trying to plot a line plot using pandas plot method, the same data with exactly same method runs fine if I use matplotlib methods, however if I use df.plot then annotate gives me error ValueError: Missing category information for StrCategoryConverter; this might be caused by unintendedly mixing categorical and numeric data
Say I have a dataframe,
data = {'Unit': {0: 'Admin ', 1: 'C-Level', 2: 'Engineering', 3: 'IT', 4: 'Manufacturing', 5: 'Sales'}, 'Mean': {0: 4.642857142857143, 1: 4.83, 2: 4.048, 3: 4.237317073170732, 4: 4.184319526627219, 5: 3.9904545454545453}}
result=pd.DataFrame(data)
When using matplotlib
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(18,9))
ax.plot(results['Unit'],results['Mean'])
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.annotate(label, val, ha='center')
plt.show()
The above code works perfectly fine.
Using pandas plot function(which gives me error)
results.plot(x = 'Unit', y = 'Mean', marker = 'o', figsize=(8,5))
ax = plt.gca()
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.annotate(label, val, ha='center')
plt.show()
which gives me error :
Traceback (most recent call last):
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\axis.py", line 1506, in convert_units
ret = self.converter.convert(x, self.units, self)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\category.py", line 49, in convert
raise ValueError(
ValueError: Missing category information for StrCategoryConverter; this might be caused by unintendedly mixing categorical and numeric data
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\backends\backend_qt.py", line 477, in _draw_idle
self.draw()
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\backends\backend_agg.py", line 436, in draw
self.figure.draw(self.renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\artist.py", line 73, in draw_wrapper
result = draw(artist, renderer, *args, **kwargs)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
return draw(artist, renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\figure.py", line 2837, in draw
mimage._draw_list_compositing_images(
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
return draw(artist, renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\axes\_base.py", line 3091, in draw
mimage._draw_list_compositing_images(
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
return draw(artist, renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\text.py", line 1969, in draw
if not self.get_visible() or not self._check_xy(renderer):
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\text.py", line 1559, in _check_xy
xy_pixel = self._get_position_xy(renderer)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\text.py", line 1552, in _get_position_xy
return self._get_xy(renderer, x, y, self.xycoords)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\text.py", line 1419, in _get_xy
x = float(self.convert_xunits(x))
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\artist.py", line 252, in convert_xunits
return ax.xaxis.convert_units(x)
File "C:\Users\hpoddar\AppData\Local\Programs\Python\Python310\lib\site-packages\matplotlib\axis.py", line 1508, in convert_units
raise munits.ConversionError('Failed to convert value(s) to axis '
matplotlib.units.ConversionError: Failed to convert value(s) to axis units: 'Admin '
Expected output :
Annotated graph
Why am I getting error in case of pandas plot, and how can I resolve the same
matplotlib.axes.Axes.annotate() takes parameter xy as below:
xy(float, float)
The point (x, y) to annotate. The coordinate system is determined by xycoords.
Therefore to fix the issue you could create a tuple that has (i, val[1]) rather than pass val which would contain string type.
ax = results.plot(x = 'Unit', y = 'Mean', marker = 'o', figsize=(8,5))
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.annotate(text=label, xy=(i, val[1]), ha='center')
Another option is to use matplotlib.axes.Axes.text():
ax = results.plot(x = 'Unit', y = 'Mean', marker = 'o', figsize=(8,5))
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.text(x=i, y=val[1], s=label, ha='center')
As you noted, when we call annotate() after matplotlib.axes.Axes.plot there is no ConversionError. But if we call annotate() after pandas.DataFrame.plot there is a ConversionError.
My best guess is that after using matplotlib to plot there will be no conversion on annotate. But with a pandas plot a conversion will be attempted. This could be due to the representation of the x-ticks being different for both cases.
To demonstrate, if we try the following code the same error will be thrown:
fig, ax = plt.subplots(figsize=(18,9))
# Call annotate without plotting! Throws ConversionError
# ax.plot(results['Unit'],results['Mean'])
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.annotate(label, val, ha='center')
Whereas if we do the following, no error will be thrown:
fig, ax = plt.subplots(figsize=(18,9))
# Call annotate without plotting! No error
# ax.plot(results['Unit'],results['Mean'])
for i, val in enumerate(zip(results['Unit'],results['Mean'])):
label = str(results.loc[i, 'Mean'])
ax.annotate(text=label, xy=(i, val[1]), ha='center')
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 trying to do a real time scatter-kind plot using matplotlib's animation module but I'm quite a newbie with it. My objective is to update the plot whenever I receive the data I want to plot, so that any time data is received, previous points disappear and the new ones are plotted.
My program can be written like this if I substitute the data receiving with a endless loop and a random generation of data:
fig = plt.figure()
skyplot = fig.add_subplot(111, projection='polar')
skyplot.set_ylim(90) # sets radius of the circle to maximum elevation
skyplot.set_theta_zero_location("N") # sets 0(deg) to North
skyplot.set_theta_direction(-1) # sets plot clockwise
skyplot.set_yticks(range(0, 90, 30)) # sets 3 concentric circles
skyplot.set_yticklabels(map(str, range(90, 0, -30))) # reverse labels
plt.ion()
while(1):
azimuths = random.sample(range(360), 8)
elevations = random.sample(range(90), 8)
colors = numpy.random.rand(3,1)
sat_plot = satellite()
ani= animation.FuncAnimation(fig, sat_plot.update, azimuths, elevations, colors)
class satellite:
def __init__(self):
self.azimuths = []
self.elevations = []
self.colors = []
self.scatter = plt.scatter(self.azimuths, self.elevations, self.colors)
def update(self, azimuth, elevation, colors):
self.azimuths = azimuth
self.elevations = elevation
return self.scatter
Right now, I'm getting the following error:
> Traceback (most recent call last):
File "./skyplot.py", line 138, in <module>
ani= animation.FuncAnimation(fig, sat_plot.update, azimuths, elevations, colors)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 442, in __init__
TimedAnimation.__init__(self, fig, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 304, in __init__
Animation.__init__(self, fig, event_source=event_source, *args, **kwargs)
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 53, in __init__
self._init_draw()
File "/usr/lib/pymodules/python2.7/matplotlib/animation.py", line 469, in _init_draw
self._drawn_artists = self._init_func()
TypeError: 'list' object is not callable
Can anyone tell me what I'm doing wrong and how could I do this?
Thanks in advance
I think you do not need an animation. You need a simple endless loop (while for example) with plot update in a thread. I can propose something like this:
import threading,time
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
data = np.random.uniform(0, 1, (5, 3))
plt.scatter(data[:, 0], data[:,1],data[:, 2]*50)
def getDataAndUpdate():
while True:
"""update data and redraw function"""
new_data = np.random.uniform(0, 1, (5, 3))
time.sleep(1)
plt.clf()
plt.scatter(new_data[:, 0], new_data[:, 1], new_data[:, 2] * 50)
plt.draw()
t = threading.Thread(target=getDataAndUpdate)
t.start()
plt.show()
The result is an animated-like figure with scatterplot.
Here is my code:
import matplotlib.pyplot as plt
plt.figure(1) # the first figure
plt.subplot(211) # the first subplot in the first figure
plt.plot([1, 2, 3])
plt.subplot(212) # the second subplot in the first figure
plt.plot([4, 5, 6])
plt.figure(2) # a second figure
plt.plot([4, 5, 6]) # creates a subplot(111) by default
plt.text(.5,1.5,'211',figure = 211) #tring to add text in previous subplot
plt.figure(1) # figure 1 current; subplot(212) still current
plt.subplot(211) # make subplot(211) in figure1 current
plt.title('Easy as 1, 2, 3') # subplot 211 title
The error:
Traceback (most recent call last):
File "C:/Users/ezhou/Desktop/python/test3.py", line 11, in <module>
plt.text(.5,1.5,'211',figure = 211)
File "C:\Python27\lib\site-packages\matplotlib\pyplot.py", line 3567, in text
ret = gca().text(x, y, s, fontdict=fontdict, withdash=withdash, **kwargs)
File "C:\Python27\lib\site-packages\matplotlib\axes\_axes.py", line 619, in text
self._add_text(t)
File "C:\Python27\lib\site-packages\matplotlib\axes\_base.py", line 1720, in _add_text
self._set_artist_props(txt)
File "C:\Python27\lib\site-packages\matplotlib\axes\_base.py", line 861, in _set_artist_props
a.set_figure(self.figure)
File "C:\Python27\lib\site-packages\matplotlib\artist.py", line 640, in set_figure
raise RuntimeError("Can not put single artist in "
RuntimeError: Can not put single artist in more than one figure
I was trying to understand the kwargs 'figure' in class matplotlib.text.Text(), but it will always reply 'Can not put single artist in more than one figure'. So I was confused about how to use this 'figure' kwarg. Can anyone give me some advise? Thanks!
You shouldn't pass figure as a kwarg, instead use text method of a Figure (or Axes) instance. Example:
import matplotlib.pyplot as plt
fig1, fig2 = plt.figure(1), plt.figure(2)
sp1, sp2 = fig1.add_subplot(211), fig2.add_subplot(211)
sp1.plot([1, 2, 3])
sp2.plot([0, 1, 3])
fig1.text(.5, .3, 'whole figure')
sp2.text(.5, .5, 'subplot')
Please note that coordinates are relative (0, 1).
P.S if you find matplotlib needlessly complicated (as I do), you may wish to have a look at Plotly
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.