Description
(Following up on gitter conversation)
Problem
The new bar_label
method is very handy, and simplifies a task that is an extremely common request on stackoverflow and elsewhere.
The only problem is that, due to some complications about including text artists in autoscaling, the annotation for the tallest bar is often either uncomfortably close to the edge of the plot or extending over it:
ax = plt.gca()
bars = ax.bar([0, 1], [1, 2])
ax.bar_label(bars)
ax = plt.gca()
bars = ax.barh([0, 1], [1000, 2000])
ax.bar_label(bars)
This is frustrating because bar_label
is very close to being a super handy automatic solution, but using it in practice requires manually setting axis limits to something reasonable.
Proposed Solution
For my own use, I have cooked up a little helper function that updates the axes data limits to include the texts objects.
ax = plt.gca()
bars = ax.bar([0, 1], [1, 2])
texts = ax.bar_label(bars)
ax.figure.canvas.draw()
for text in texts:
text_bbox = text.get_window_extent().corners()
ax.update_datalim(ax.transData.inverted().transform(text_bbox))
ax.autoscale_view()
There was some concern raised on gitter that this approach is not fully general because it doesn't handle situations where, because the numbers are too large (and hence wide) or the font is too big, the annotations can't actually fit in the allotted axes space. Although in that case, my code does not blow up, it just gives a result that looks crazy in a fairly-understandable way.
But I do think that something like this (ideally as the default behavior, but possibly as an option) is needed to make bar_label
actually useful as an "automatic bar labeling" solution.
Additional context and prior art
#19429 is related, although the proposed solution there (do normal clipping on the annotations) would actually exacerbate this issue