-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
pyplot.savefig fails with ValueError: cannot convert float NaN to integer #4318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The problem here seems to do with plotting very small numbers. with Anyway for completeness I get the following warnings for both
with
import matplotlib.pyplot as plt
from scipy.stats import norm as scipy_stats_norm
from math import sqrt
import numpy as np
fig, ax = plt.subplots()
mean = -0.0938
stdev = sqrt(0.008812)
max_x = 1100 # this fails
#max_x = 1000 # this works
x = np.linspace(-max_x, max_x, 300)
y = scipy_stats_norm.pdf(x, loc=mean, scale=stdev)
ax.plot(x, y)
ax.set_xlim(-max_x, max_x)
#filename = '/tmp/fail.png'
#plt.savefig(filename, bbox_inches='tight')
plt.show() |
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 In [47]: np.max(y)
Out[47]: 7.9084499991689783e-317 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. |
Adding |
Hmm, slightly different numbers, what system do you use? I work on debian jessie 64bit python 2.7.9 |
Ubuntu beta (varient?, something with a v) but using py3k from anaconda. |
and 32bit or 64bit? oh, I see what you mean... In [1]: import numpy as np
In [2]: np.MachAr(float).xmin
Out[2]: 2.2250738585072014e-308 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 |
I remember seeing an issue go by on numpy a while ago which was talking On Wed, Apr 8, 2015 at 8:43 AM OceanWolf notifications@github.com wrote:
|
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. |
@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. |
The trace back is raised from in side a text draw inside an axis draw It would also be worth looking if the same thing happens with one of the On Wed, Apr 8, 2015, 12:40 OceanWolf notifications@github.com wrote:
|
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 This So yes, I think we need to change the code to detect singularity from something like |
desingularization happens in the autoscaling, IIRC. So, it would be prior On Wed, Apr 8, 2015 at 3:14 PM, OceanWolf notifications@github.com wrote:
|
Ahh yes, found it, the |
Yes, this line, I don't get it: if vmax - vmin <= max(abs(vmin), abs(vmax)) * tiny: shouldn't it just read: if vmax - vmin <= 1/np.MachAr(float).xmax: what do I miss? |
For plotting purposes, we don't necessarily want to go to the minimum possible fp number; to be meaningful, a range of numbers has to be bigger than that. Also, if and when the ultimate small value check is appropriate, wouldn't one use the xmin attribute instead of 1/xmax? When the autoscaling check occurs, what are the values of vmax and vmin? If they are both denormalized, is their difference a NaN, in which case the test would evaluate to False and the singularity would not be detected? If this is the case, the solution is to form the vmax-vmin difference first, and flag the singularity based on |
@efiring as far as I can tell denormalised numbers work fine for all operations, the problem here comes from overflow caused by the asymmetry introduced by allowing denormalised numbers, i.e., that Thus to ensure we don't cause an overflow in the scaling factor we need to ensure: 1/(vmax - vmin) <= np.MachAr(float).xmax or rearranging: vmax - vmin <= 1/np.MachAr(float).xmax Of course we may want to add additional wiggle room there, something like: vmax - vmin <= factor/np.MachAr(float).xmax |
Yes, it works! But I needed to use a factor. Basically the method above prevents the overflow warning, but later on in the Thus when I test with a Not sure why it doesn't throw an error during |
@OceanWolf Is there a PR that goes with this? |
@tacaswell not yet, I have only made the diagnosis, and I don't have time at the moment to make a decent fix (i.e. one that doesn't limit subnormals), see my last comment for ideas. |
Punted as this seems like a corner case and looks involved to fix. |
@OceanWolf, by "doesn't limit subnormals", do you mean allowing plot ranges that are in the subnormal domain? We don't need to do this. All we need is a robust system for covering reasonably small ranges, and never generating an exception. This is a matter of plotting library default autoscaling strategy, not ultimate numerics. |
BUG: when autoscaling, handle tiny but non-zero values; closes #4318
@OceanWolf, Thanks for your diagnoses and explanations, which were very helpful. Also, I didn't know about np.MachAr() until you pointed it out. |
@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): from matplotlib import pyplot as plt
plt.plot([1000, 1001, 1002]) # scales with m = 1, c = -1000
plt.show() |
I was able to reproduce the issue: #!/usr/bin/env python3
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
d = {'job': list(range(1, 3)),
'duration': [83066.639344, 820.700000],
'type': ['A', 'B']}
df = pd.DataFrame(d)
plot = sns.catplot(x="duration", y="job", data=df, hue='type',
color="b", kind="bar", height=3, aspect=4)
ax = plot.axes.flat[0]
for p in plt.gca().patches:
ax.text(p.get_width(),
p.get_y() + p.get_height() / 2,
p.get_width())
plot.savefig("barplot.png") Here's the full stacktrace:
Any workaround for it? |
@dzieciou Your issue is that you create a text at a
Workarounds:
|
@ImportanceOfBeingErnest, your comment saved me some time tracking this down! Since the issue was data dependent in my case and I had several
Maybe |
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... |
Great. I should have checked master... |
No problem! I just wanted it on the record here so folks don’t try to track this bug down. |
This error also shows when using
When I comment out
The solution:Add vmin and vmax:
|
@zxdawn Can you please open a new issue with that example and include the version information? |
@tacaswell OK, submit to #15093 . |
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:
Here's the result:
The text was updated successfully, but these errors were encountered: