Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Possible regression in 1.2.1 vs 1.2.0 re bar plot with log=True #1882

Closed
y-p opened this Issue · 17 comments

5 participants

@y-p
y-p commented

The following worked in 1.2.0, but dies in 1.2.1 with the following:

In [3]: plt.bar([0,1],[2,3],log=True)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-9389ad3e6e82> in <module>()
----> 1 plt.bar([0,1],[2,3],log=True)

/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.pyc in bar(left, height, width, bottom, hold, **kwargs)
   2381         ax.hold(hold)
   2382     try:
-> 2383         ret = ax.bar(left, height, width=width, bottom=bottom, **kwargs)
   2384         draw_if_interactive()
   2385     finally:

/usr/local/lib/python2.7/dist-packages/matplotlib/axes.pyc in bar(self, left, height, width, bottom, **kwargs)
   4899             r.get_path()._interpolation_steps = 100
   4900             #print r.get_label(), label, 'label' in kwargs
-> 4901             self.add_patch(r)
   4902             patches.append(r)
   4903 

/usr/local/lib/python2.7/dist-packages/matplotlib/axes.pyc in add_patch(self, p)
   1568         if p.get_clip_path() is None:
   1569             p.set_clip_path(self.patch)
-> 1570         self._update_patch_limits(p)
   1571         self.patches.append(p)
   1572         p._remove_method = lambda h: self.patches.remove(h)

/usr/local/lib/python2.7/dist-packages/matplotlib/axes.pyc in _update_patch_limits(self, patch)
   1586         vertices = patch.get_path().vertices
   1587         if vertices.size > 0:
-> 1588             xys = patch.get_patch_transform().transform(vertices)
   1589             if patch.get_data_transform() != self.transData:
   1590                 patch_to_data = (patch.get_data_transform() -

/usr/local/lib/python2.7/dist-packages/matplotlib/patches.pyc in get_patch_transform(self)
    579 
    580     def get_patch_transform(self):
--> 581         self._update_patch_transform()
    582         return self._rect_transform
    583 

/usr/local/lib/python2.7/dist-packages/matplotlib/patches.pyc in _update_patch_transform(self)
    575         width = self.convert_xunits(self._width)
    576         height = self.convert_yunits(self._height)
--> 577         bbox = transforms.Bbox.from_bounds(x, y, width, height)
    578         self._rect_transform = transforms.BboxTransformTo(bbox)
    579 

/usr/local/lib/python2.7/dist-packages/matplotlib/transforms.pyc in from_bounds(x0, y0, width, height)
    784         *width* and *height* may be negative.
    785         """
--> 786         return Bbox.from_extents(x0, y0, x0 + width, y0 + height)
    787 
    788     @staticmethod

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
@y-p y-p referenced this issue in pydata/pandas
Closed

log=True bar plots are raising with mpl 1.2.1 #3254

@tacaswell
Owner

I can confirm this.

@tacaswell tacaswell referenced this issue from a commit in tacaswell/matplotlib
@tacaswell tacaswell re-added lines to make sure that `bottom` and `left` are not None in
the case of `log=True`.  If this is not done, there will be type
exceptions.

Issue #1882
2eb17ab
@tacaswell
Owner

A work-around for this is to include the bottom kwarg.

I think this bug was introduced in f6dfcea . In the block that deals with if bottom is None does not set bottom to be a non-None value if log==True.

@neggert, can you take a look at this?

@y-p
y-p commented

I just recently fixed a bug having to do with missing bars when
specifying log=True at the same time as bottom, am I missing
something or is that another bug?

with 1.10, (and 1.2.0 as well IIRC):

a

a solution that requires different invocations for different mpl versions
would be a real problem.

@y-p
y-p commented

Let me put it this way. Say a library has to support mpl 1.10 , 1.20 and 1.20.1.
right now, to get a log bar plot:
1. passing log=True and no bottom args gives you a plot <= 1.20, exception on 1.20.1
2. passing log=True and specifying bottom arg vanishes the bars <= 1.20

Your PR (correct me if I'm wrong) would make it so that starting with 1.20.1
to get a log bar blot I have to specify bottom and for earlier versions
I must not specify the bottom arg. that's a terrible solution, unless
there's an extra trick to getting 2. working on earlier versions.

@tacaswell
Owner

This conversation is now happening on two threads.

The PR fixes it so that 1. behaves correctly in all cases. The work around is to make stuff work before the patch is applied, and the work around is to not rely on default values and thus should also work on all versions of mpl.

I can not reproduce your 2.

@y-p
y-p commented

it's happening right here.
ok, so the PR takes care of 1.20.2 on, and the workaround is supposed to fix
the problem for users of 1.20.1 while keeping earlier versions working. good,
but 2. still reproduces on my box every time, so the workaround fails in a different
way for me.
2. is what I get with ipython qtconsole --pylab inline, which is a common enough
environment, and the bug fixed (which prompted this issue) was to mitigate an identical
report from another user experiencing 2.

@tacaswell
Owner

ok, I misunderstood and was looking at the wrong version, now that I looked in the right place I see it. It looks like the issues with clipping got fixed someplace between 1.2.0 and 1.2.1 (hence why using a bottom of 0 worked when I tested the work-around on 1.2.x)

What (I think) will work in all cases is

plt.bar([0,1],[5,5000],log=True, bottom=[1, 1])

but this requires that you know something sensible about where the bottom of your graph should be. Maybe something like

ydata = [5, 5000]
plt.bar([0,1],ydata,log=True, bottom=10 ** np.floor(np.log10(np.min(ydata))))

For before 1.2.1 you just can't specify bottom=0, any other positive value should work fine.

@tacaswell tacaswell referenced this issue from a commit in tacaswell/matplotlib
@tacaswell tacaswell re-added lines to make sure that `bottom` and `left` are not None in
the case of `log=True`.  If this is not done, there will be type
exceptions.

Issue #1882
d6e3734
@y-p
y-p commented

The case I need working always has the bars anchored at the bottom of the graph.
a 1 pixel offset at the bottom is pretty much invisible, I think that would work fine, thanks.

@y-p
y-p commented

The 1 pixel workaround seems to work fine for single plots, but I may have
uncovered another regression. Not sure if related or not:

In [1]: fig,ax=plt.subplots(2)
   ...: ax[0].bar(0,5,0.8,log=True, bottom=1,label='a')
   ...: ax[0].bar(1,5000,0.8,log=True, bottom=1,label='a')
   ...: ax[0].axhline(0, color='k', linestyle='--')
Out[1]: <matplotlib.lines.Line2D at 0x38b21d0>

1.2.0

a120

1.2.1

a121

@tacaswell
Owner

This happens on 1.2.1, but does not happen on master (1.3.x).

To be fair, adding a line at 0 on a log graph isn't meaningful.

@neggert

Trying to get up to speed on this.

@y-p If I understand correctly, your example:

ax = plt.bar([0,1],[5,5000],log=True,bottom=[0,0])

has been broken for a while. Before f6dfcea, if you didn't pass the bottom keyword, it was set to [1e-100] as a workaround. f6dfcea attempted to fix the root cause by passing nonposy="clip" when setting the log scale. In the process, it introduced another bug which causes a crash when log=True and bottom isn't specified. #1889 fixes that problem. With that PR, these should both work properly:

ax = plt.bar([0,1],[5,5000],log=True,bottom=[0,0])
ax = plt.bar([0,1],[5,5000].log=True)

This process will lead to different behavior on v1.2.0, v1.2.1, and v1.2.2, but I think given the nature of the bugs, that's unavoidable. @tacaswell's solution should work on all 3, however. This is an area that wasn't covered by the tests, which I'll rectify when I get time.

Have I understood and addressed your first issue?

As for your second issue, I suspect this is related to using nonposy="clip". I'll look into it. As @tacaswell mentioned, putting a line at 0 on a log plot isn't meaningful, so I'm not sure what the expected behavior is here.

@y-p
y-p commented

That's right, though I need to make sure the bottom=epsilon(data) doesn't throw off the yaxis ticks.
if bottom=None will work again starting from the next release (so anything but 1.2.1 will work)
could be simpler to just sniff the version and use bottom=0 for 1.2.1 only,

with 1.2.1:
s

a cross-version solution for the second issue would be welcome as well. could move
to another issue but they seem related. whatever you prefer.

Thanks for the help so far.

@neggert

Let's move that to another issue. That way this can be closed once #1889 is merged.

@y-p
y-p commented

done, #1892 .

@tacaswell
Owner

can this get flagged as known 1.2.1 bug?

@WeatherGod
Collaborator

done... milestoned it as 1.2.x known bugs.

@tacaswell
Owner

This can also be closed, fixed by #1889

@mdboom mdboom closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.