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