@@ -3039,22 +3039,20 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3039
3039
"""
3040
3040
Make a grouped bar plot.
3041
3041
3042
- .. note::
3042
+ .. versionadded:: 3.11
3043
+
3043
3044
This function is new in v3.11, and the API is still provisional.
3044
3045
We may still fine-tune some aspects based on user-feedback.
3045
3046
3046
- This is a convenience function to plot bars for multiple datasets.
3047
- In particular, it simplifies positioning of the bars compared to individual
3048
- `~.Axes.bar` plots.
3049
-
3050
- Bar plots present categorical data as a sequence of bars, one bar per category.
3051
- We call one set of such values a *dataset* and it's bars all share the same
3052
- color. Grouped bar plots show multiple such datasets, where the values per
3053
- category are grouped together. The category names are drawn as tick labels
3054
- below the bar groups. Each dataset has a distinct bar color, and can optionally
3055
- get a label that is used for the legend.
3047
+ Grouped bar charts visualize a collection of multiple categorical datasets.
3048
+ A categorical dataset is a mapping *name* -> *value*. The values of the
3049
+ dataset are represented by a sequence of bars of the same color.
3050
+ In a grouped bar chart, the bars of all datasets are grouped together by
3051
+ category. The category names are drawn as tick labels next to the bar group.
3052
+ Each dataset has a distinct bar color, and can optionally get a label that
3053
+ is used for the legend.
3056
3054
3057
- Here is an example call structure and the corresponding plot :
3055
+ Example :
3058
3056
3059
3057
.. code-block:: python
3060
3058
@@ -3087,25 +3085,20 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3087
3085
- dict of array-like: A mapping from names to datasets. Each dataset
3088
3086
(dict value) must have the same number of elements.
3089
3087
3090
- This is similar to passing a list of array-like, with the addition that
3091
- each dataset gets a name.
3092
-
3093
3088
Example call:
3094
3089
3095
3090
.. code-block:: python
3096
3091
3097
- grouped_bar({'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]})
3092
+ data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2}
3093
+ grouped_bar(data_dict)
3098
3094
3099
- The names are used as *labels*, i.e. the following two calls are
3100
- equivalent:
3095
+ The names are used as *labels*, i.e. this is equivalent to
3101
3096
3102
3097
.. code-block:: python
3103
3098
3104
- data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]}
3105
- grouped_bar(data_dict)
3106
3099
grouped_bar(data_dict.values(), labels=data_dict.keys())
3107
3100
3108
- When using a dict-like input, you must not pass *labels* explicitly.
3101
+ When using a dict input, you must not pass *labels* explicitly.
3109
3102
3110
3103
- a 2D array: The rows are the categories, the columns are the different
3111
3104
datasets.
@@ -3120,30 +3113,31 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3120
3113
3121
3114
.. code-block:: python
3122
3115
3123
- group_labels = ["group_A ", "group_B "]
3116
+ categories = ["A ", "B "]
3124
3117
dataset_labels = ["dataset_0", "dataset_1", "dataset_2"]
3125
3118
array = np.random.random((2, 3))
3126
-
3127
- Note that this is consistent with pandas. These two calls produce
3128
- the same bar plot structure:
3129
-
3130
- .. code-block:: python
3131
-
3132
3119
grouped_bar(array, tick_labels=categories, labels=dataset_labels)
3133
- df = pd.DataFrame(array, index=categories, columns=dataset_labels)
3134
- df.plot.bar()
3135
3120
3136
3121
- a `pandas.DataFrame`.
3137
3122
3123
+ The index is used for the categories, the columns are used for the
3124
+ datasets.
3125
+
3138
3126
.. code-block:: python
3139
3127
3140
3128
df = pd.DataFrame(
3141
- np.random.random((2, 3))
3142
- index=["group_A ", "group_B "],
3129
+ np.random.random((2, 3)),
3130
+ index=["A ", "B "],
3143
3131
columns=["dataset_0", "dataset_1", "dataset_2"]
3144
3132
)
3145
3133
grouped_bar(df)
3146
3134
3135
+ i.e. this is equivalent to
3136
+
3137
+ .. code-block::
3138
+
3139
+ grouped_bar(df.to_numpy(), tick_labels=df.index, labels=df.columns)
3140
+
3147
3141
Note that ``grouped_bar(df)`` produces a structurally equivalent plot like
3148
3142
``df.plot.bar()``.
3149
3143
@@ -3153,22 +3147,21 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3153
3147
3154
3148
tick_labels : list of str, optional
3155
3149
The category labels, which are placed on ticks at the center *positions*
3156
- of the bar groups.
3157
-
3158
- If not set, the axis ticks (positions and labels) are left unchanged.
3150
+ of the bar groups. If not set, the axis ticks (positions and labels) are
3151
+ left unchanged.
3159
3152
3160
3153
labels : list of str, optional
3161
3154
The labels of the datasets, i.e. the bars within one group.
3162
3155
These will show up in the legend.
3163
3156
3164
3157
group_spacing : float, default: 1.5
3165
- The space between two bar groups in units of bar width.
3158
+ The space between two bar groups as multiples of bar width.
3166
3159
3167
3160
The default value of 1.5 thus means that there's a gap of
3168
3161
1.5 bar widths between bar groups.
3169
3162
3170
3163
bar_spacing : float, default: 0
3171
- The space between bars in units of bar width.
3164
+ The space between bars as multiples of bar width.
3172
3165
3173
3166
orientation : {"vertical", "horizontal"}, default: "vertical"
3174
3167
The direction of the bars.
@@ -3215,7 +3208,7 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3215
3208
aspects. ``bar(x, y)`` is a lower-level API and places bars with height *y*
3216
3209
at explicit positions *x*. It also allows to specify individual bar widths
3217
3210
and colors. This kind of detailed control and flexibility is difficult to
3218
- manage and often not needed when plotting multiple datasets as grouped bar
3211
+ manage and often not needed when plotting multiple datasets as a grouped bar
3219
3212
plot. Therefore, ``grouped_bar`` focusses on the abstraction of bar plots
3220
3213
as visualization of categorical data.
3221
3214
@@ -3275,8 +3268,18 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3275
3268
heights = heights .T
3276
3269
3277
3270
num_datasets = len (heights )
3278
- dataset_0 = next (iter (heights ))
3279
- num_groups = len (dataset_0 )
3271
+ num_groups = len (next (iter (heights ))) # inferred from first dataset
3272
+
3273
+ # validate that all datasets have the same length, i.e. num_groups
3274
+ # - can be skipped if heights is an array
3275
+ if not hasattr (heights , 'shape' ):
3276
+ for i , dataset in enumerate (heights ):
3277
+ if len (dataset ) != num_groups :
3278
+ raise ValueError (
3279
+ "'heights' contains datasets with different number of "
3280
+ f"elements. dataset 0 has { num_groups } elements but "
3281
+ f"dataset { i } has { len (dataset )} elements."
3282
+ )
3280
3283
3281
3284
if positions is None :
3282
3285
group_centers = np .arange (num_groups )
@@ -3291,13 +3294,6 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
3291
3294
else :
3292
3295
group_distance = 1
3293
3296
3294
- for i , dataset in enumerate (heights ):
3295
- if len (dataset ) != num_groups :
3296
- raise ValueError (
3297
- f"'x' indicates { num_groups } groups, but dataset { i } "
3298
- f"has { len (dataset )} groups"
3299
- )
3300
-
3301
3297
_api .check_in_list (["vertical" , "horizontal" ], orientation = orientation )
3302
3298
3303
3299
if colors is None :
0 commit comments