In the definition of the function barh of matplotlib:
matplotlib.pyplot.barh(bottom, width, height=0.8, left=None, hold=None, **kwargs)
The default "height" is 0.8, but when I draw some figures with different Figure's height for example (30, 40,..) and dpi=100. I see the Bar's height is changed. It's not fixed. So I wonder what is the unit of the height in barh and how to make it fixed (not depend on figure's height).
barh (y, width, height=0.8, left=None, *, align='center', **kwargs)[source] Make a horizontal bar plot. The bars are positioned at y with the given alignment. Their dimensions are given by width and height. The horizontal baseline is left (default 0).
barh() Function. The Axes. barh() function in axes module of matplotlib library is used to make a horizontal bar plot.
Syntax of matplotlib. It is an optional attribute, by default the figure has the dimensions as (6.4, 4.8). This is a standard plot where the attribute is not mentioned in the function. Normally each unit inch is of 80 x 80 pixels.
I'll split this into two parts:
I wonder what is the unit of the height in barh
(Apparently people have been wondering this since 2009... so I guess you're in good company!)
This question is the easier part - it's a percentage of the height allotted to the bar in the figure. For example, the default height=0.8
means the height of the bar will be 0.8 * (plot_height / n_bars)
. You can see this by setting height=1.0
(or even a value > 1, the bars will overlap).
If you really want to be sure, here's the source of axes.barh
. This just calls axes.bar
- take a look at these lines:
nbars = len(bottom)
if len(left) == 1:
left *= nbars
if len(height) == 1:
height *= nbars
And later on...
args = zip(left, bottom, width, height, color, edgecolor, linewidth)
for l, b, w, h, c, e, lw in args:
if h < 0:
b += h
h = abs(h)
if w < 0:
l += w
w = abs(w)
r = mpatches.Rectangle(
xy=(l, b), width=w, height=h,
facecolor=c,
edgecolor=e,
linewidth=lw,
label='_nolegend_',
margins=margins
)
r.update(kwargs)
r.get_path()._interpolation_steps = 100
#print r.get_label(), label, 'label' in kwargs
self.add_patch(r)
patches.append(r)
So you see the height is scaled by nbars
, and when you draw the rectangle they are spaced out by this height.
how to make it fixed
This is harder, you will have to manually set it. The bars on the chart are ultimately matplotlib.patches.Rectangle
objects, which have a width and height... which is also a percentage. I think the best solution is to compute the appropriate percentage manually.
Here's a short example, based off a barh demo:
import matplotlib.pyplot as plt
plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt
# Example data
people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')
y_pos = np.arange(len(people))
performance = 3 + 10 * np.random.rand(len(people))
error = np.random.rand(len(people))
plt.figure(figsize=(5,5), dpi=80)
myplot = plt.barh(y_pos, performance, height=0.8, xerr=error, align='center', alpha=0.4)
plt.yticks(y_pos, people)
plt.xlabel('Performance')
plt.title('How fast do you want to go today?')
for obj in myplot:
# Let's say we want to set height of bars to always 5px..
desired_h = 5
current_h = obj.get_height()
current_y = obj.get_y()
pixel_h = obj.get_verts()[2][1] - obj.get_verts()[0][1]
print("current position = ", current_y)
print("current pixel height = ", pixel_h)
# (A) Use ratio of pixels to height-units to calculate desired height
h = desired_h / (pixel_h/current_h)
obj.set_height(h)
pixel_h = obj.get_verts()[2][1] - obj.get_verts()[0][1]
print("now pixel height = ", pixel_h)
# (B) Move the rectangle so it still aligns with labels and error bars
y_diff = current_h - h # height is same units as y
new_y = current_y + y_diff/2
obj.set_y(new_y)
print("now position = ", obj.get_y())
plt.show()
Part A calculates pixel_h/current_h
to get a conversion between pixels and height-units. Then we can divide desired_h
(pixels) by that ratio to obtain desired_h
in height-units. This sets the bar width to 5 px, but the bottom of the bar stays in the same place, so it's no longer aligned with the labels and error bars.
Part B calculates the new y position. Since y
and height
are in the same units, we can just add half the height difference (y_diff
) to get the new position. This keeps the bar centered around whatever original y-position it had.
Note that this only sets the initial size. If you resize the plot, for example, the bars will still scale - you'd have to override that event to resize the bars appropriately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With