
Description
Bug report
Bug summary
Guided by this tutorial example user could expect that the same applies for any graphing function with the keyword orientation
. This isn't the default case when dealing with bar
. Specifying orientation
keyword does not produce a rotated bar graph without manually setting the required parameters to avoid an error. To achieve the desired result barh
has to be used.
Code for reproduction
import matplotlib.pyplot as plt
#import numpy as np
#N = 5
#img = np.random.randn(N, N)
#xs = img.sum(axis=0)
#ys = img.sum(axis=1)
#bins = np.arange(0, N, 1)
img = [[-0.13448386, -0.92189708, -0.3883107 , 1.83910067, 0.46092219],
[-0.29775299, 0.4623531 , -0.53428658, 0.82103232, -0.66423673],
[ 1.4559248 , -0.74152634, -0.10229999, 1.12182625, -0.20793333],
[-1.38758209, 0.61128182, -1.34506956, -0.5511364 , 0.50791828],
[ 1.29593156, 0.28209814, 1.60556993, 0.71651822, 0.11639 ]]
xs = [ 0.93203742, -0.30769036, -0.7643969 , 3.94734105, 0.21306041]
ys = [ 0.85533123, -0.21289089, 1.5259914 , -2.16458795, 4.01650784]
bins = [0, 1, 2, 3, 4]
fig = plt.figure()
plt.subplot(221)
plt.bar(left=None, height=0.8, bottom=bins, width=ys,
orientation="horizontal")
plt.subplot(222)
plt.bar(bins, ys, orientation="horizontal")
plt.subplot(223)
plt.barh(bins, ys)
plt.subplot(224)
plt.bar(bins, xs)
plt.show()
Actual outcome
Current output for the above code will fail with an error.
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/test.py", line 18, in <module>
plt.bar(bins, ys, orientation="horizontal")
File "/usr/local/lib/python2.7/dist-packages/matplotlib/pyplot.py", line 2705, in bar
**kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/__init__.py", line 1892, in inner
return func(ax, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py", line 2075, in bar
"be length %d or scalar" % nbars)
ValueError: incompatible sizes: argument 'left' must be length 1 or scalar
Expected outcome
- First graph (subplot 221, top left) will not produce an error and represents the currently correct usage with orientation
horizontal
. It's here to show that this isn't a bug, just weird usage (API). - Second graph (subplot 222, top right) will produce said error. The error happens because the default parameter order is
bar(self, left, height, width=0.8, bottom=None, **kwargs):
soleft
andheight
are set by default instead of being dependent onorientation
keyword in which case sometimesbottom
andwidth
parameters should be set instead, andheight
should becomewidth
. Error is raised when the methodbar
checks data for consistency but doesn't find any. - Third graph (subplot 223, bottom left) output should be the same as first two - nothing should be broken for backward compatibility issues as well as the fact that histogram with
bar
option andhorizontal
orientation secretly callsbarh
for drawing. - Fourth graph (subplot 224, bottom right) is the
vertical
orientation and should display correctly after the changes.
Proposed change
In the case when bar
is called with left
and horizontal
orientation:
- values in
bottom
andleft
parameters should be exchanged - values in
width
andheight
should be exchanged
Changes affect the axes/_axes.py
file line no. 2034 where I propose that the values are manually exchanged, as in the code below, between the parameters before _process_unit_info
is called, that is immediately after elif orientation == "horizontal"
line:
if _left is not None:
_bottom, bottom, _left, left = _left, left, _bottom, bottom
width, height = height, width
Once this is implemented the listed examples above produce the expected result.
As a final thought I believe that solution is a bit "hackish" because it makes it harder to track data in the code for future devs/users as the switch happens relatively late inside bar
. On the other hand its more user friendly because it reduces the amount of knowledge users have to have about how mpl works on the inside and makes it possible to more intuitively work with the mpl's API. In practice I believe code should be refactored to remove barh and standardize the orientation
keyword to work even in the cases of line plots or scatter plots. In principle this would consist of just a function that would switch the x
and y
data parameters. This would not be a very friendly change, and a bit of an overkill, as old code depending on barh
would not work anyomre and at the same time a lot of mpl's code already seems to depend on the bar barh difference to work properly.
Additionally, I have no idea if this change breaks something else, but so far it dosen't seem to have hurt my installation very much.
Matplotlib version
- Matplotlib version 2.0.0, installed from pip, numpy version 1.7.1
- Python 2.7.6
Sorry if this was an issue before, I looked but found none.