Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[Bug]: RuntimeError when bar_label of stacked bar chart comes to rest outside of plot's Y limit #25625

Closed
@Lavode

Description

@Lavode

Bug summary

When creating a stacked bar chart and annotating its components by use of the bar_label method, a RuntimeError("Unknown return type") exception is raised the moment one of the bar labels comes to rest outside the specified Y limits.

Code for reproduction

#!/usr/bin/env python3

from matplotlib import pyplot
import numpy as np

def main():
    categories = ["Foo", "Bar", "Baz", "Barbaz"]
    data = {
            "Apples": [0, 1, 2, 3],
            "Oranges": [2, 5, 27, 1],
            "Pears": [17, 22, 15, 10],
    }

    grid = (1, 1)
    fig = pyplot.figure(figsize=(9, 9), dpi=300, layout="constrained")
    ax = pyplot.subplot2grid(grid, (0, 0), fig=fig)

    bottom = np.zeros(len(categories))
    width = 0.5

    for fruit, values in data.items():
        p = ax.bar(
                categories,
                values,
                width,
                label=fruit,
                bottom=bottom,
        )

        ax.bar_label(p, label_type='center')

        bottom += values


    # The exception happens if the Y-limit of the plot is chosen too low.

    # This limit is fine, the whole graph fits
    # ax.set(ylim=(0, 50))

    # This limit is fine as well, even though it cuts off the top of the
    # topmost bar.
    # ax.set(ylim=(0, 35))

    # This limit is fine still, with the topmost label ('15' of the 'Baz'
    # category) being on the top border of the plot.
    # ax.set(ylim=(0, 29))

    # This limit produces an exception, likely as the topmost label ('15' of
    # the 'Baz' category) cannot be placed anymore, since its bar's lower
    # end starts at 2+27 = 29.
    ax.set(ylim=(0, 28))

    fig.savefig("/tmp/matplotlib_example.png", format="png")

if __name__ == '__main__':
    main()

Actual outcome

(matplotlib-bar-label-mre)matplotlib-bar-label-mre › python demo.py 
Traceback (most recent call last):
  File "/home/michael/dev/python/matplotlib-bar-label-mre/demo.py", line 56, in <module>
    main()
  File "/home/michael/dev/python/matplotlib-bar-label-mre/demo.py", line 53, in main
    fig.savefig("/tmp/matplotlib_example.png", format="png")
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/figure.py", line 3343, in savefig
    self.canvas.print_figure(fname, **kwargs)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/backend_bases.py", line 2342, in print_figure
    self.figure.draw(renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/artist.py", line 95, in draw_wrapper
    result = draw(artist, renderer, *args, **kwargs)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/artist.py", line 72, in draw_wrapper
    return draw(artist, renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/figure.py", line 3134, in draw
    self.get_layout_engine().execute(self)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/layout_engine.py", line 253, in execute
    return do_constrained_layout(fig, w_pad=w_pad, h_pad=h_pad,
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/_constrained_layout.py", line 119, in do_constrained_layout
    make_layout_margins(layoutgrids, fig, renderer, h_pad=h_pad,
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/_constrained_layout.py", line 369, in make_layout_margins
    pos, bbox = get_pos_and_bbox(ax, renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/_constrained_layout.py", line 617, in get_pos_and_bbox
    tightbbox = martist._get_tightbbox_for_layout_only(ax, renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/artist.py", line 1415, in _get_tightbbox_for_layout_only
    return obj.get_tightbbox(*args, **{**kwargs, "for_layout_only": True})
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/axes/_base.py", line 4408, in get_tightbbox
    bbox = a.get_tightbbox(renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 2064, in get_tightbbox
    return super().get_tightbbox(renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/artist.py", line 367, in get_tightbbox
    bbox = self.get_window_extent(renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 2050, in get_window_extent
    self.update_positions(self._renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 1954, in update_positions
    self.set_transform(self._get_xy_transform(renderer, self.anncoords))
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 1538, in _get_xy_transform
    xy0 = self._get_ref_xy(renderer)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 1569, in _get_ref_xy
    return self._get_xy(renderer, *self.xy, self.xycoords)
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 1478, in _get_xy
    return self._get_xy_transform(renderer, s).transform((x, y))
  File "/home/michael/.local/share/virtualenvs/matplotlib-bar-label-mre/lib/python3.10/site-packages/matplotlib/text.py", line 1496, in _get_xy_transform
    raise RuntimeError("Unknown return type")
RuntimeError: Unknown return type

Expected outcome

I'd expect the corresponding section of the bar, along with its label, to simply be outside the visible plot area. Or at least a more descriptive error message.

Additional information

The exception seems to happen the moment one of the bar labels cannot fit in the visible plot area anymore. This can be seen by starting with a large Y limit, and slowly lowering it.

As the Y limit approaches the position of the topmost label, it will be shifted down on its own. However the moment the Y limit is set low enough that the topmost bar's component is fully outside the visible area, the exception arises.

The (mostly) minimal reproducible example above contains several Y limits to indicate this happening.

Operating system

Arch Linux, Linux 6.2.5

Matplotlib Version

3.7.1

Matplotlib Backend

TkAgg

Python version

3.10.9

Jupyter version

Not applicable

Installation

pip

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions