@@ -3073,22 +3073,19 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3073
3073
"""
3074
3074
Make a grouped bar plot.
3075
3075
3076
- .. note::
3076
+ .. versionadded:: 3.11
3077
+
3077
3078
This function is new in v3.11, and the API is still provisional.
3078
3079
We may still fine-tune some aspects based on user-feedback.
3079
3080
3080
- This is a convenience function to plot bars for multiple datasets.
3081
- In particular, it simplifies positioning of the bars compared to individual
3082
- `~.Axes.bar` plots.
3083
-
3084
3081
Bar plots present categorical data as a sequence of bars, one bar per category.
3085
- We call one set of such values a *dataset* and it's bars all share the same
3082
+ We call one set of such values a *dataset* and its bars all share the same
3086
3083
color. Grouped bar plots show multiple such datasets, where the values per
3087
3084
category are grouped together. The category names are drawn as tick labels
3088
3085
below the bar groups. Each dataset has a distinct bar color, and can optionally
3089
3086
get a label that is used for the legend.
3090
3087
3091
- Here is an example call structure and the corresponding plot :
3088
+ Example :
3092
3089
3093
3090
.. code-block:: python
3094
3091
@@ -3121,25 +3118,20 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3121
3118
- dict of array-like: A mapping from names to datasets. Each dataset
3122
3119
(dict value) must have the same number of elements.
3123
3120
3124
- This is similar to passing a list of array-like, with the addition that
3125
- each dataset gets a name.
3126
-
3127
3121
Example call:
3128
3122
3129
3123
.. code-block:: python
3130
3124
3131
- grouped_bar({'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]})
3125
+ data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2}
3126
+ grouped_bar(data_dict)
3132
3127
3133
- The names are used as *labels*, i.e. the following two calls are
3134
- equivalent:
3128
+ The names are used as *labels*, i.e. this is equivalent to
3135
3129
3136
3130
.. code-block:: python
3137
3131
3138
- data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]}
3139
- grouped_bar(data_dict)
3140
3132
grouped_bar(data_dict.values(), labels=data_dict.keys())
3141
3133
3142
- When using a dict-like input, you must not pass *labels* explicitly.
3134
+ When using a dict input, you must not pass *labels* explicitly.
3143
3135
3144
3136
- a 2D array: The rows are the categories, the columns are the different
3145
3137
datasets.
@@ -3154,30 +3146,31 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3154
3146
3155
3147
.. code-block:: python
3156
3148
3157
- group_labels = ["group_A ", "group_B "]
3149
+ categories = ["A ", "B "]
3158
3150
dataset_labels = ["dataset_0", "dataset_1", "dataset_2"]
3159
3151
array = np.random.random((2, 3))
3160
-
3161
- Note that this is consistent with pandas. These two calls produce
3162
- the same bar plot structure:
3163
-
3164
- .. code-block:: python
3165
-
3166
3152
grouped_bar(array, tick_labels=categories, labels=dataset_labels)
3167
- df = pd.DataFrame(array, index=categories, columns=dataset_labels)
3168
- df.plot.bar()
3169
3153
3170
3154
- a `pandas.DataFrame`.
3171
3155
3156
+ The index is used for the categories, the columns are used for the
3157
+ datasets.
3158
+
3172
3159
.. code-block:: python
3173
3160
3174
3161
df = pd.DataFrame(
3175
- np.random.random((2, 3))
3176
- index=["group_A ", "group_B "],
3162
+ np.random.random((2, 3)),
3163
+ index=["A ", "B "],
3177
3164
columns=["dataset_0", "dataset_1", "dataset_2"]
3178
3165
)
3179
3166
grouped_bar(df)
3180
3167
3168
+ i.e. this is equivalent to
3169
+
3170
+ .. code-block::
3171
+
3172
+ grouped_bar(df.to_numpy(), tick_labels=df.index, labels=df.columns)
3173
+
3181
3174
Note that ``grouped_bar(df)`` produces a structurally equivalent plot like
3182
3175
``df.plot.bar()``.
3183
3176
@@ -3187,22 +3180,21 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3187
3180
3188
3181
tick_labels : list of str, optional
3189
3182
The category labels, which are placed on ticks at the center *positions*
3190
- of the bar groups.
3191
-
3192
- If not set, the axis ticks (positions and labels) are left unchanged.
3183
+ of the bar groups. If not set, the axis ticks (positions and labels) are
3184
+ left unchanged.
3193
3185
3194
3186
labels : list of str, optional
3195
3187
The labels of the datasets, i.e. the bars within one group.
3196
3188
These will show up in the legend.
3197
3189
3198
3190
group_spacing : float, default: 1.5
3199
- The space between two bar groups in units of bar width.
3191
+ The space between two bar groups as multiples of bar width.
3200
3192
3201
3193
The default value of 1.5 thus means that there's a gap of
3202
3194
1.5 bar widths between bar groups.
3203
3195
3204
3196
bar_spacing : float, default: 0
3205
- The space between bars in units of bar width.
3197
+ The space between bars as multiples of bar width.
3206
3198
3207
3199
orientation : {"vertical", "horizontal"}, default: "vertical"
3208
3200
The direction of the bars.
@@ -3249,7 +3241,7 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3249
3241
aspects. ``bar(x, y)`` is a lower-level API and places bars with height *y*
3250
3242
at explicit positions *x*. It also allows to specify individual bar widths
3251
3243
and colors. This kind of detailed control and flexibility is difficult to
3252
- manage and often not needed when plotting multiple datasets as grouped bar
3244
+ manage and often not needed when plotting multiple datasets as a grouped bar
3253
3245
plot. Therefore, ``grouped_bar`` focusses on the abstraction of bar plots
3254
3246
as visualization of categorical data.
3255
3247
@@ -3309,8 +3301,18 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3309
3301
heights = heights .T
3310
3302
3311
3303
num_datasets = len (heights )
3312
- dataset_0 = next (iter (heights ))
3313
- num_groups = len (dataset_0 )
3304
+ num_groups = len (next (iter (heights ))) # inferred from first dataset
3305
+
3306
+ # validate that all datasets have the same length, i.e. num_groups
3307
+ # - can be skipped if heights is an array
3308
+ if not hasattr (heights , 'shape' ):
3309
+ for i , dataset in enumerate (heights ):
3310
+ if len (dataset ) != num_groups :
3311
+ raise ValueError (
3312
+ "'heights' contains datasets with different number of "
3313
+ f"elements. dataset 0 has { num_groups } elements but "
3314
+ f"dataset { i } has { len (dataset )} elements."
3315
+ )
3314
3316
3315
3317
if positions is None :
3316
3318
group_centers = np .arange (num_groups )
@@ -3325,13 +3327,6 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3325
3327
else :
3326
3328
group_distance = 1
3327
3329
3328
- for i , dataset in enumerate (heights ):
3329
- if len (dataset ) != num_groups :
3330
- raise ValueError (
3331
- f"'x' indicates { num_groups } groups, but dataset { i } "
3332
- f"has { len (dataset )} groups"
3333
- )
3334
-
3335
3330
_api .check_in_list (["vertical" , "horizontal" ], orientation = orientation )
3336
3331
3337
3332
if colors is None :
0 commit comments