@@ -3066,8 +3066,8 @@ def broken_barh(self, xranges, yrange, **kwargs):
30663066 return col
30673067
30683068 @_docstring .interpd
3069- def grouped_bar (self , x , heights , * , group_spacing = 1.5 , bar_spacing = 0 ,
3070- labels = None , orientation = "vertical" , colors = None ,
3069+ def grouped_bar (self , heights , * , positions = None , group_spacing = 1.5 , bar_spacing = 0 ,
3070+ tick_labels = None , labels = None , orientation = "vertical" , colors = None ,
30713071 ** kwargs ):
30723072 """
30733073 Make a grouped bar plot.
@@ -3080,25 +3080,24 @@ def grouped_bar(self, x, heights, *, group_spacing=1.5, bar_spacing=0,
30803080 into one Axes. In particular, it simplifies positioning of the bars
30813081 compared to individual `~.Axes.bar` plots.
30823082
3083+ Terminology: A bar *group* is a set of bars drawn next to each other. They
3084+ can be associated with a group name, which is visualized as the tick label
3085+ below that group. A *dataset* is a set of values, one for each bar group.
3086+ This means *dataset_0* will be rendered as the first bar in each bar group.
3087+
3088+ .. plot:: _embedded_plots/grouped_bar.py
3089+
30833090 Parameters
30843091 ----------
3085- x : array-like or list of str
3086- The center positions of the bar groups. If these are numeric values,
3087- they have to be equidistant. As with `~.Axes.bar`, you can provide
3088- categorical labels, which will be used at integer numeric positions
3089- ``range(x)``.
3090-
30913092 heights : list of array-like or dict of array-like or 2D array
30923093 The heights for all x and groups. One of:
30933094
30943095 - list of array-like: A list of datasets, each dataset must have
3095- ``len(x)`` elements.
3096+ the same number of elements.
30963097
30973098 .. code-block:: none
30983099
3099- x = ["a", "b"]
3100-
3101- # x[0] x[1]
3100+ # group_A group_B
31023101 dataset_0 = [ds0_a, ds0_b]
31033102 dataset_1 = [ds1_a, ds1_b]
31043103 dataset_2 = [ds2_a, ds2_b]
@@ -3107,24 +3106,24 @@ def grouped_bar(self, x, heights, *, group_spacing=1.5, bar_spacing=0,
31073106
31083107 Example call::
31093108
3110- grouped_bar(x, [dataset_0, dataset_1, dataset_2])
3109+ grouped_bar([dataset_0, dataset_1, dataset_2])
31113110
31123111 - dict of array-like: A mapping names to datasets. Each dataset
3113- (dict value) must have ``len(x)`` elements.
3112+ (dict value) must have the same number of elements elements.
31143113
31153114 This is similar to passing a list of array-like, with the addition that
31163115 each dataset gets a name.
31173116
31183117 Example call::
31193118
3120- grouped_bar(x, {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]})
3119+ grouped_bar({'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]})
31213120
31223121 The names are used as *labels*, i.e. the following two calls are
31233122 equivalent::
31243123
31253124 data_dict = {'ds0': dataset_0, 'ds1': dataset_1, 'ds2': dataset_2]}
3126- grouped_bar(x, data_dict)
3127- grouped_bar(x, data_dict.values(), labels=data_dict.keys())
3125+ grouped_bar(data_dict)
3126+ grouped_bar(data_dict.values(), labels=data_dict.keys())
31283127
31293128 When using a dict-like input, you must not pass *labels* explicitly.
31303129
@@ -3133,33 +3132,41 @@ def grouped_bar(self, x, heights, *, group_spacing=1.5, bar_spacing=0,
31333132 .. code-block:: none
31343133
31353134 dataset_0 dataset_1 dataset_2
3136- x[0]="a" ds0_a ds1_a ds2_a
3137- x[1]="b" ds0_b ds1_b ds2_b
3135+ group_A ds0_a ds1_a ds2_a
3136+ group_B ds0_b ds1_b ds2_b
31383137
31393138 .. code-block::
31403139
3141- x = ["a ", "b "]
3140+ group_labels = ["group_A ", "group_B "]
31423141 dataset_labels = ["dataset_0", "dataset_1", "dataset_2"]
31433142 array = np.random.random((2, 3))
31443143
31453144 Note that this is consistent with pandas. These two calls produce
31463145 the same bar plot structure::
31473146
3148- grouped_bar(x, array, labels=dataset_labels)
3149- pd.DataFrame(array, index=x, columns=dataset_labels).plot.bar()
3147+ grouped_bar(array, tick_labels=group_labels, labels=dataset_labels)
3148+ df = pd.DataFrame(array, index=group_labels, columns=dataset_labels)
3149+ df.plot.bar()
31503150
3151- group_spacing : float
3152- The space between two bar groups in units of bar width.
3151+ positions : array-like, optional
3152+ The center positions of the bar groups. The values have to be equidistant.
3153+ If not given, a sequence of integer positions 0, 1, 2, ... is used.
31533154
3154- bar_spacing : float
3155- The space between bars in units of bar width.
3155+ tick_labels: list of str, optional
3156+ The group labels, which are placed on ticks at the center *positions*
3157+ of the bar groups.
31563158
3157- labels : array-like of str, optional
3159+ If not set, the axis ticks (positions and labels) are left unchanged.
3160+
3161+ labels : list of str, optional
31583162 The labels of the datasets, i.e. the bars within one group.
31593163 These will show up in the legend.
31603164
3161- Note: The "other" label dimension are the group labels, which
3162- can be set via *x*.
3165+ group_spacing : float
3166+ The space between two bar groups in units of bar width.
3167+
3168+ bar_spacing : float
3169+ The space between bars in units of bar width.
31633170
31643171 orientation : {"vertical", "horizontal"}, default: "vertical"
31653172 The direction of the bars.
@@ -3196,27 +3203,26 @@ def grouped_bar(self, x, heights, *, group_spacing=1.5, bar_spacing=0,
31963203 raise ValueError (
31973204 "'labels' cannot be used if 'heights' are a mapping" )
31983205 labels = heights .keys ()
3199- heights = heights .values ()
3206+ heights = list ( heights .values () )
32003207 elif hasattr (heights , 'shape' ):
32013208 heights = heights .T
32023209
3203- num_groups = len (x )
32043210 num_datasets = len (heights )
3211+ dataset_0 = next (iter (heights ))
3212+ num_groups = len (dataset_0 )
32053213
3206- if isinstance (x [0 ], str ):
3207- tick_labels = x
3214+ if positions is None :
32083215 group_centers = np .arange (num_groups )
32093216 group_distance = 1
32103217 else :
3211- if num_groups > 1 :
3212- d = np .diff (x )
3218+ group_centers = np .asanyarray (positions )
3219+ if len (group_centers ) > 1 :
3220+ d = np .diff (group_centers )
32133221 if not np .allclose (d , d .mean ()):
3214- raise ValueError ("'x ' must be equidistant" )
3222+ raise ValueError ("'positions ' must be equidistant" )
32153223 group_distance = d [0 ]
32163224 else :
32173225 group_distance = 1
3218- group_centers = np .asarray (x )
3219- tick_labels = None
32203226
32213227 for i , dataset in enumerate (heights ):
32223228 if len (dataset ) != num_groups :
0 commit comments