Repository navigation
Closed
Description
I think this is happening because I am plotting a gaussian that is very narrow compared to the x range. Still it seems failing here is bad behavior.
here is some code that reproduces the problem, taken from IPython notebook:
%matplotlib inline
import matplotlib.pyplot as plt
from scipy.stats import norm as scipy_stats_norm
from math import sqrt
plt.clf()
fig, ax = plt.subplots()
max_x = 1100 # this fails
#max_x = 1000 # this works
x = np.linspace(-max_x, max_x, 300)
mean = -0.0938
stdev = sqrt(0.008812)
ax.plot(x, scipy_stats_norm.pdf(x, loc=mean, scale=stdev), color='red', linewidth=2)
ax.set_yticklabels([])
ax.set_xlim(-max_x, max_x)
filename = '/tmp/fail.png'
plt.savefig(filename, bbox_inches='tight')
plt.show()Here's the result:
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/pyplot.py", line 561, in savefig
return fig.savefig(*args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/figure.py", line 1421, in savefig
self.canvas.print_figure(*args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/backend_bases.py", line 2167, in print_figure
**kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 505, in print_png
FigureCanvasAgg.draw(self)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 451, in draw
self.figure.draw(self.renderer)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/figure.py", line 1034, in draw
func(*args)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/axes.py", line 2086, in draw
a.draw(renderer)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/axis.py", line 1096, in draw
tick.draw(renderer)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/axis.py", line 241, in draw
self.label1.draw(renderer)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/artist.py", line 55, in draw_wrapper
draw(artist, renderer, *args, **kwargs)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/text.py", line 598, in draw
ismath=ismath, mtext=self)
File "/opt/datasci-python/lib/python2.7/site-packages/matplotlib/backends/backend_agg.py", line 188, in draw_text
font.get_image(), np.round(x - xd), np.round(y + yd) + 1, angle, gc)
ValueError: cannot convert float NaN to integer
Activity
OceanWolf commentedon Apr 8, 2015
The problem here seems to do with plotting very small numbers. with
max_x = 1000, it gives only two non-zero values out of 300, 1.72083369e-260 and 2.05807755e-291; and withmax_x = 1100only one, 7.90845000e-317. Naturally if you change, 300 to 301 then the error does not occur, but that goes beside the point. Matplotlib should not give such errors when plotting small numbers.Anyway for completeness I get the following warnings for both
plt.showandplt.savefigwith
savefigadditionally throwing the assertion errortacaswell commentedon Apr 8, 2015
Oddly, the error seems to be coming out of drawing the tick labels.
The issue here seems to be that this is pushing the limits of floats. On my system I only get 1 non-zero value which is
which is notably smaller than what http://docs.scipy.org/doc/numpy/reference/generated/numpy.MachAr.html#numpy.MachAr claims the smallest float should be which makes me think something awful is going on with non-normal floats (and I am now out of my depth on the numerics side of things.).
I think the solution is to make sure we do a better job making sure that auto-limits are non-singular.
tacaswell commentedon Apr 8, 2015
Adding
ax.set_ylim(0, 1e-300)'fixes' this problem.OceanWolf commentedon Apr 8, 2015
Hmm, slightly different numbers, what system do you use? I work on debian jessie 64bit python 2.7.9
tacaswell commentedon Apr 8, 2015
Ubuntu beta (varient?, something with a v) but using py3k from anaconda.
OceanWolf commentedon Apr 8, 2015
and 32bit or 64bit?
oh, I see what you mean...
So, a possible bug in numpy? Combined with a possible bug in matplotlib. I mean if numpy gives us numbers that shouldn't exist, then that would explain why our calculations fail. I think we should first get some clarification from numpy about this and then decide how to patch it (atm I think doing a test based around
(x < np.MachAr().xmin).any(), but I would want to hear from numpy first).tacaswell commentedon Apr 8, 2015
I remember seeing an issue go by on numpy a while ago which was talking
about 'denormal' floats (http://en.wikipedia.org/wiki/Denormal_number) so I
don't think it is a bug in numpy. If the top and bottom of the range are
the same we have some code that make the range non-singular, but it seems
that this is falling in the gap of what triggers that code path and what
works.
On Wed, Apr 8, 2015 at 8:43 AM OceanWolf notifications@github.com wrote:
OceanWolf commentedon Apr 8, 2015
Thanks for the link, so definitly a matplotlib bug, but I still think a bug in numpy exists over MachAr... I have just submitted a bug on this to numpy numpy/numpy#5755.
OceanWolf commentedon Apr 8, 2015
@tacaswell forgive my ignorance, but what made you say that it came from the ticks? The overflow error appears from doing a transform for drawing a line:
Nothing changes with respect to this bug when I add:
Pardon my poor knowledge of the draw code, I only know the backends well atm.
tacaswell commentedon Apr 8, 2015
The trace back is raised from in side a text draw inside an axis draw
inside an axes draw.
It would also be worth looking if the same thing happens with one of the
vector backend s
On Wed, Apr 8, 2015, 12:40 OceanWolf notifications@github.com wrote:
OceanWolf commentedon Apr 8, 2015
Ahh, the traceback from there, I looked at the first problem, the overflow error, so I stuck a traceback in that line of code... that error happens in
BboxTransformFrom.get_matrixand does 1/<y_canvas_max> but as subnormal only extends the minimum exponent, we get an overflow when taking the reciprocal.This
BboxTransformFrom.get_matrixtransforms all points from grid space to canvas space, and thus gets called when plotting the line.So yes, I think we need to change the code to detect singularity from something like
if dy == 0: raise Errortoif dy < 1/np.MachAr(float).xmax: raise Error. I currently hunt for that line that tests singularity, I have found some very close to the source but only do so on DEBUG, and have now just found a line inaxes._base.set_ylimthat looks like it, but putting in print statements and passing in a true singular set of data to plot, (i.e. not just from a computational perspective), it has already done so before, so now I will trace up until I find the source of the de-singularisation of the bounding box :).WeatherGod commentedon Apr 8, 2015
desingularization happens in the autoscaling, IIRC. So, it would be prior
to the draw()/show().
On Wed, Apr 8, 2015 at 3:14 PM, OceanWolf notifications@github.com wrote:
OceanWolf commentedon Apr 8, 2015
Ahh yes, found it, the
transforms.nonsingularfunction.12 remaining items
Merge pull request #4717 from efiring/nonsingular
efiring commentedon Jul 17, 2015
@OceanWolf, Thanks for your diagnoses and explanations, which were very helpful. Also, I didn't know about np.MachAr() until you pointed it out.
OceanWolf commentedon Jul 17, 2015
@efiring rereading, I meant that we need do need to properly deal with small ranges, and if we do that I think we can safely plot subnormals for plotting.
I think we just need to some linear rescaling, x' = mx + c, on par with what we do at the moment for ranges, i.e similar to what we already have with this code (at least visually, I haven't looked at the internals):
dzieciou commentedon Nov 6, 2018
I was able to reproduce the issue:
Here's the full stacktrace:
Any workaround for it?
ImportanceOfBeingErnest commentedon Nov 6, 2018
@dzieciou Your issue is that you create a text at a
nanposition. A minimal example would beWorkarounds:
bbox_inches="tight"(the default for seaborn), but ratherplot.savefig("barplot.png", bbox_inches=None).ulrichstern commentedon Mar 17, 2019
@ImportanceOfBeingErnest, your comment saved me some time tracking this down! Since the issue was data dependent in my case and I had several
plt.text(), this wrapper was useful:Maybe
plt.text()should do something similar by default; it currently appears to allow whatplt.savefig()cannot handle. (I tested only with matplotlib 2.2.4, though, the latest version pip updated to.)jklymak commentedon Mar 18, 2019
Just to be clear, this bug doesn't exist in master anymore because we now check the bboxes for finite-values before we add them to the tightbbox calculations...
ulrichstern commentedon Mar 18, 2019
Great. I should have checked master...
jklymak commentedon Mar 18, 2019
No problem! I just wanted it on the record here so folks don’t try to track this bug down.
zxdawn commentedon Aug 19, 2019
This error also shows when using
tight_layoutwith nan value.Here's an example:
When I comment out
plt.tight_layout(w_pad=0.1, h_pad=1), I got this:The solution:
Add vmin and vmax:
tacaswell commentedon Aug 20, 2019
@zxdawn Can you please open a new issue with that example and include the version information?
zxdawn commentedon Aug 21, 2019
@tacaswell OK, submit to #15093 .