@@ -3039,22 +3039,20 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
30393039 """
30403040 Make a grouped bar plot.
30413041
3042- .. note::
3042+ .. versionadded:: 3.11
3043+
30433044 This function is new in v3.11, and the API is still provisional.
30443045 We may still fine-tune some aspects based on user-feedback.
30453046
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.
30563054
3057- Here is an example call structure and the corresponding plot :
3055+ Example :
30583056
30593057 .. code-block:: python
30603058
@@ -3087,25 +3085,20 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
30873085 - dict of array-like: A mapping from names to datasets. Each dataset
30883086 (dict value) must have the same number of elements.
30893087
3090- This is similar to passing a list of array-like, with the addition that
3091- each dataset gets a name.
3092-
30933088 Example call:
30943089
30953090 .. code-block:: python
30963091
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)
30983094
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
31013096
31023097 .. code-block:: python
31033098
3104- data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]}
3105- grouped_bar(data_dict)
31063099 grouped_bar(data_dict.values(), labels=data_dict.keys())
31073100
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.
31093102
31103103 - a 2D array: The rows are the categories, the columns are the different
31113104 datasets.
@@ -3120,30 +3113,31 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
31203113
31213114 .. code-block:: python
31223115
3123- group_labels = ["group_A ", "group_B "]
3116+ categories = ["A ", "B "]
31243117 dataset_labels = ["dataset_0", "dataset_1", "dataset_2"]
31253118 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-
31323119 grouped_bar(array, tick_labels=categories, labels=dataset_labels)
3133- df = pd.DataFrame(array, index=categories, columns=dataset_labels)
3134- df.plot.bar()
31353120
31363121 - a `pandas.DataFrame`.
31373122
3123+ The index is used for the categories, the columns are used for the
3124+ datasets.
3125+
31383126 .. code-block:: python
31393127
31403128 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 "],
31433131 columns=["dataset_0", "dataset_1", "dataset_2"]
31443132 )
31453133 grouped_bar(df)
31463134
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+
31473141 Note that ``grouped_bar(df)`` produces a structurally equivalent plot like
31483142 ``df.plot.bar()``.
31493143
@@ -3153,22 +3147,21 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
31533147
31543148 tick_labels : list of str, optional
31553149 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.
31593152
31603153 labels : list of str, optional
31613154 The labels of the datasets, i.e. the bars within one group.
31623155 These will show up in the legend.
31633156
31643157 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.
31663159
31673160 The default value of 1.5 thus means that there's a gap of
31683161 1.5 bar widths between bar groups.
31693162
31703163 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.
31723165
31733166 orientation : {"vertical", "horizontal"}, default: "vertical"
31743167 The direction of the bars.
@@ -3215,7 +3208,7 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
32153208 aspects. ``bar(x, y)`` is a lower-level API and places bars with height *y*
32163209 at explicit positions *x*. It also allows to specify individual bar widths
32173210 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
32193212 plot. Therefore, ``grouped_bar`` focusses on the abstraction of bar plots
32203213 as visualization of categorical data.
32213214
@@ -3275,8 +3268,18 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
32753268 heights = heights .T
32763269
32773270 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+ )
32803283
32813284 if positions is None :
32823285 group_centers = np .arange (num_groups )
@@ -3291,13 +3294,6 @@ def grouped_bar(self, heights, *, positions=None, group_spacing=1.5, bar_spacing
32913294 else :
32923295 group_distance = 1
32933296
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-
33013297 _api .check_in_list (["vertical" , "horizontal" ], orientation = orientation )
33023298
33033299 if colors is None :
0 commit comments