PyPlot bar crashes with Log=True - python

I'm trying to do a simple logarithmic bar plot:
import matplotlib.pyplot as plt
plt.bar(range(10), [4**i for i in range(10)], log=True)
plt.show()
It crashes with:
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\pyplot.py", line 2383, in bar
ret = ax.bar(left, height, width=width, bottom=bottom, **kwargs)
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\axes.py", line 4903, in bar
self.add_patch(r)
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\axes.py", line 1572, in add_patch
self._update_patch_limits(p)
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\axes.py", line 1590, in _update_patch_limits
xys = patch.get_patch_transform().transform(vertices)
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\patches.py", line 582, in get_patch_transform
self._update_patch_transform()
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\patches.py", line 578, in _update_patch_transform
bbox = transforms.Bbox.from_bounds(x, y, width, height)
File "C:\Program Files (x86)\Python33\lib\site-packages\matplotlib\transforms.py", line 786, in from_bounds
return Bbox.from_extents(x0, y0, x0 + width, y0 + height)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
When I use log=False, it works. I treid plt.yscale('log'), but then the bars disappeared. I'dont see, how I could use the log Parameter wrong in such a simple case.

This appears to be a bug in your version of matplotlib. While the default for the parameter bottom of plt.bar is claimed to be 0, adding an extra keyword argument sets bottom=None which subsequently leads to arithmetic using bottom to fail.
As a workaround you can set bottom yourself to the default value again.
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(10)
plt.bar(x, 4**x, bottom=0, log=True)
plt.show()

Related

Update Line2D properties from line on different axes in matplotlib

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

How to fix error running local Otsu threshold example?

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.

Basemap TypeError: input must be an array, list, tuple or scalar

I'm trying to create a map visualization using the basemap module in Python 3.0 but when I try to plot this figure I get the TypeError:
TypeError: input must be an array, list, tuple or scalar
My code looks like this:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.basemap import Basemap
data = pd.ExcelFile('C:\\Users\\...xlsx')
data_input = pd.read_excel(data, 'Sheet2')
# Extract the data we're interested in
lat = data_input['value1'].values
lon = data_input['value2'].values
capacity = data_input['value3'].values
# 1. Draw the map background
fig = plt.figure(figsize=(8, 8))
m = Basemap(projection='lcc', resolution='h',
lat_0=31.1351682, lon_0=-99.3350553,
width=1.3E6, height=1.25E6)
m.shadedrelief()
m.drawcoastlines(color='gray')
m.drawcountries(color='gray')
m.drawstates(color='gray')
# 2. scatter city data, with color reflecting population
# and size reflecting area
m.scatter(lon, lat, latlon=True,
c=np.log10(capacity), s=capacity,
cmap='Reds', alpha=0.5)
I've tried changing all the inputs to data_input.values, data_input.to_list(), list(data_input) and just using the default pandas Series.
The error traceback occurs here:
File "<ipython-input-6-3a66206674c7>", line 3, in <module>
cmap='Reds', alpha=0.5)
File "C:\Users\...Continuum\anaconda3\lib\site-packages\mpl_toolkits\basemap\__init__.py", line 566, in with_transform
x, y = self(x,y)
File "C:\Users\...\Continuum\anaconda3\lib\site-packages\mpl_toolkits\basemap\__init__.py", line 1191, in __call__
xout,yout = self.projtran(x,y,inverse=inverse)
File "C:\Users\...\Continuum\anaconda3\lib\site-packages\mpl_toolkits\basemap\proj.py", line 288, in __call__
outx,outy = self._proj4(x, y, inverse=inverse)
File "C:\Users\...\Continuum\anaconda3\lib\site-packages\pyproj\__init__.py", line 397, in __call__
inx, xisfloat, xislist, xistuple = _copytobuffer(lon)
File "C:\Users\...\Continuum\anaconda3\lib\site-packages\pyproj\__init__.py", line 652, in _copytobuffer
raise TypeError('input must be an array, list, tuple or scalar')
No matter what form it gets it doesn't work. What am I missing here?

Memory error in pyplot hist

I have a list size of 1247746130. I want to get a histogram for this list:
bins = np.linspace(-100, 1, 100)
plt.hist(refList, bins, alpha=0.5, label='reference')
plt.legend(loc='upper right')
plt.savefig('reference.png')
but I get an error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 3081, in hist
stacked=stacked, data=data, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/__init__.py", line 1898, in inner
return func(ax, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py", line 6146, in hist
x = _normalize_input(x, 'x')
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py", line 6083, in _normalize_input
inp = np.asarray(inp)
File "/usr/local/lib/python2.7/dist-packages/numpy/core/numeric.py", line 531, in asarray
return array(a, dtype, copy=False, order=order)
MemoryError
I have 8GB RAM. Is it somehow possible to get a histogram for my data?
Thanks in advance!
I've had problems with plt.hist in the past so now use numpy.histogram. (although I think plt.hist does actually use numpy.histogram behind the scenes). An example is shown below:
import numpy as np
import matplotlib.pyplot as plt
bins = np.linspace(-100, 1, 100)
heights, edges = np.histogram(data, bins)
edges = edges[:-1]+(edges[1]-edges[0])
fig, ax = plt.subplots()
ax.plot(edges, heights)
plt.show()

Matplotlib runs out of memory when plotting in a loop

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.

Categories