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

y-p opened this Issue Apr 3, 2013 · 17 comments


None yet
5 participants

y-p commented Apr 3, 2013

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)

/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)
    580     def get_patch_transform(self):
--> 581         self._update_patch_transform()
    582         return self._rect_transform

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

/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)
    788     @staticmethod

TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'

y-p referenced this issue in pandas-dev/pandas Apr 3, 2013


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


tacaswell commented Apr 9, 2013

I can confirm this.

@tacaswell tacaswell added a commit to tacaswell/matplotlib that referenced this issue Apr 9, 2013

@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

Issue #1882

tacaswell commented Apr 9, 2013

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 commented Apr 9, 2013

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 solution that requires different invocations for different mpl versions
would be a real problem.

y-p commented Apr 9, 2013

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 commented Apr 9, 2013

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 commented Apr 9, 2013

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 commented Apr 9, 2013

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 added a commit to tacaswell/matplotlib that referenced this issue Apr 9, 2013

@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

Issue #1882

y-p commented Apr 9, 2013

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 commented Apr 9, 2013

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>






tacaswell commented Apr 9, 2013

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 commented Apr 9, 2013

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 commented Apr 9, 2013

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:

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 commented Apr 9, 2013

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

y-p commented Apr 9, 2013

done, #1892 .


tacaswell commented Apr 17, 2013

can this get flagged as known 1.2.1 bug?


WeatherGod commented Apr 18, 2013

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


tacaswell commented May 21, 2013

This can also be closed, fixed by #1889

mdboom closed this May 21, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment