Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions lib/matplotlib/axes/_axes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2453,6 +2453,15 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
linewidth = kwargs.pop('linewidth', None)
hatch = kwargs.pop('hatch', None)

# store style for an empty data scenario that would otherwise be lost.
legend_fallback_kwargs = {
'facecolor': facecolor[0] if len(facecolor) else 'none',
'edgecolor': edgecolor,
'linewidth': linewidth,
'label': '_nolegend_',
'hatch': hatch,
}

# Because xerr and yerr will be passed to errorbar, most dimension
# checking and processing will be left to the errorbar method.
xerr = kwargs.pop('xerr', None)
Expand Down Expand Up @@ -2618,6 +2627,14 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
self.add_patch(r)
patches.append(r)

if not patches:
legend_fallback = mpatches.Rectangle(
xy=(0, 0), width=0, height=0,
**legend_fallback_kwargs)
legend_fallback._internal_update(kwargs)
else:
legend_fallback = None

if xerr is not None or yerr is not None:
if orientation == 'vertical':
# using list comps rather than arrays to preserve unit info
Expand Down Expand Up @@ -2646,6 +2663,7 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
bar_container = BarContainer(patches, errorbar, datavalues=datavalues,
orientation=orientation,
label=bar_container_label)
bar_container._legend_fallback = legend_fallback
self.add_container(bar_container)

if tick_labels is not None:
Expand Down
2 changes: 2 additions & 0 deletions lib/matplotlib/legend_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ def legend_artist(self, legend, orig_handle, fontsize, handlebox)

def update_from_first_child(tgt, src):
first_child = next(iter(src.get_children()), None)
if first_child is None:
first_child = getattr(src, '_legend_fallback', None)
if first_child is not None:
tgt.update_from(first_child)

Expand Down
33 changes: 33 additions & 0 deletions lib/matplotlib/tests/test_legend.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,39 @@ def test_empty_bar_chart_with_legend():
plt.legend()


def test_empty_bar_chart_legend_style():
# issue #21506
Comment on lines +666 to +667

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_empty_bar_chart_legend_style():
# issue #21506
def test_empty_bar_chart_legend_style():

_, ax = plt.subplots()
ax.bar([], [], color='red', alpha=0.3, label='empty')
assert mpl.colors.same_color(
ax.legend().legend_handles[0].get_facecolor(),
mpl.colors.to_rgba('red', 0.3),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can pass this directly instead of eager resolving it.

Suggested change
mpl.colors.to_rgba('red', 0.3),
('red', 0.3),

)

_, ax = plt.subplots()
ax.bar([], [], label='a')
ax.bar([], [], label='b')
handles = ax.legend().legend_handles
assert mpl.colors.same_color(handles[0].get_facecolor(), 'C0')
assert mpl.colors.same_color(handles[1].get_facecolor(), 'C1')

_, ax = plt.subplots()
ax.bar([], [],
facecolor='red', edgecolor='black', linewidth=3,
label='styled', hatch='//')
handle = ax.legend().legend_handles[0]
assert mpl.colors.same_color(handle.get_edgecolor(), 'black')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should you not be checking facecolor as well?

assert handle.get_linewidth() == 3
assert handle.get_hatch() == '//'

_, ax = plt.subplots()
ax.barh([], [], color='green', label='h')
assert mpl.colors.same_color(
ax.legend().legend_handles[0].get_facecolor(),
'green',
)


@image_comparison(['shadow_argument_types.png'], remove_text=True, style='mpl20',
tol=0 if platform.machine() == 'x86_64' else 0.028)
def test_shadow_argument_types():
Expand Down
Loading