Skip to content

Commit 7241d40

Browse files
committed
Add support for numeric x
1 parent 1212500 commit 7241d40

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

galleries/examples/lines_bars_and_markers/grouped_bar_chart.py

+16
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,19 @@
102102
#
103103
# df = pd.DataFrame(data, index=x, columns=columns)
104104
# df.plot.bar()
105+
106+
# %%
107+
# Numeric x values
108+
# ----------------
109+
# In the most common case, one will want to pass categorical labels as *x*.
110+
# Additionally, we allow numeric values for *x*, as with `~.Axes.bar()`.
111+
# But for simplicity and clarity, we require that these are equidistant.
112+
113+
x = [0, 2, 4]
114+
data = {
115+
'data1': [1, 2, 3],
116+
'data2': [1.2, 2.2, 3.2],
117+
}
118+
119+
fig, ax = plt.subplots()
120+
ax.grouped_bar(x, data)

lib/matplotlib/axes/_axes.py

+26-9
Original file line numberDiff line numberDiff line change
@@ -3004,8 +3004,12 @@ def grouped_bar(self, x, heights, dataset_labels=None):
30043004
"""
30053005
Parameters
30063006
-----------
3007-
x : array-like of str
3008-
The labels.
3007+
x : array-like or list of str
3008+
The center positions of the bar groups. If these are numeric values,
3009+
they have to be equidistant. As with `~.Axes.bar`, you can provide
3010+
categorical labels, which will be used at integer numeric positions
3011+
``range(x)``.
3012+
30093013
heights : list of array-like or dict of array-like or 2D array
30103014
The heights for all x and groups. One of:
30113015
@@ -3064,27 +3068,40 @@ def grouped_bar(self, x, heights, dataset_labels=None):
30643068
elif hasattr(heights, 'shape'):
30653069
heights = heights.T
30663070

3067-
num_labels = len(x)
3071+
num_groups = len(x)
30683072
num_datasets = len(heights)
30693073

3070-
for dataset in heights:
3071-
assert len(dataset) == num_labels
3074+
if isinstance(x[0], str):
3075+
tick_labels = x
3076+
group_centers = np.arange(num_groups)
3077+
else:
3078+
if num_groups > 1:
3079+
d = np.diff(x)
3080+
if not np.allclose(d, d.mean()):
3081+
raise ValueError("'x' must be equidistant")
3082+
group_centers = np.asarray(x)
3083+
tick_labels = None
3084+
3085+
for i, dataset in enumerate(heights):
3086+
if len(dataset) != num_groups:
3087+
raise ValueError(
3088+
f"'x' indicates {num_groups} groups, but dataset {i} "
3089+
f"has {len(dataset)} groups"
3090+
)
30723091

30733092
margin = 0.1
30743093
bar_width = (1 - 2 * margin) / num_datasets
3075-
block_centers = np.arange(num_labels)
30763094

30773095
if dataset_labels is None:
30783096
dataset_labels = [None] * num_datasets
30793097
else:
30803098
assert len(dataset_labels) == num_datasets
30813099

30823100
for i, (hs, dataset_label) in enumerate(zip(heights, dataset_labels)):
3083-
lefts = block_centers - 0.5 + margin + i * bar_width
3084-
print(i, x, lefts, hs, dataset_label)
3101+
lefts = group_centers - 0.5 + margin + i * bar_width
30853102
self.bar(lefts, hs, width=bar_width, align="edge", label=dataset_label)
30863103

3087-
self.xaxis.set_ticks(block_centers, labels=x)
3104+
self.xaxis.set_ticks(group_centers, labels=tick_labels)
30883105

30893106
# TODO: does not return anything for now
30903107

0 commit comments

Comments
 (0)