@@ -3000,6 +3000,94 @@ def broken_barh(self, xranges, yrange, **kwargs):
3000
3000
3001
3001
return col
3002
3002
3003
+ def grouped_bar (self , x , heights , dataset_labels = None ):
3004
+ """
3005
+ Parameters
3006
+ -----------
3007
+ x : array-like of str
3008
+ The labels.
3009
+ heights : list of array-like or dict of array-like or 2D array
3010
+ The heights for all x and groups. One of:
3011
+
3012
+ - list of array-like: A list of datasets, each dataset must have
3013
+ ``len(x)`` elements.
3014
+
3015
+ .. code-block:: none
3016
+
3017
+ x = ['a', 'b']
3018
+ group_labels = ['ds0', 'ds1', 'ds2']
3019
+
3020
+ # group_labels: ds0 ds1 dw2
3021
+ heights = [dataset_0, dataset_1, dataset_2]
3022
+
3023
+ # x[0] x[1]
3024
+ dataset_0 = [ds0_a, ds0_b]
3025
+
3026
+ # x[0] x[1]
3027
+ heights = [[ds0_a, ds0_b], # dataset_0
3028
+ [ds1_a, ds1_b], # dataset_1
3029
+ [ds2_a, ds2_b], # dataset_2
3030
+ ]
3031
+
3032
+ - dict of array-like: A names to datasets, each dataset (dict value)
3033
+ must have ``len(x)`` elements.
3034
+
3035
+ group_labels = heights.keys()
3036
+ heights = heights.values()
3037
+
3038
+ - a 2D array: columns map to *x*, columns are the different datasets.
3039
+
3040
+ .. code-block:: none
3041
+
3042
+ dataset_0 dataset_1 dataset_2
3043
+ x[0]='a' ds0_a ds1_a ds2_a
3044
+ x[1]='b' ds0_b ds1_b ds2_b
3045
+
3046
+ Note that this is consistent with pandas. These two calls produce
3047
+ the same bar plot structure::
3048
+
3049
+ grouped_bar(x, array, group_labels=group_labels)
3050
+ pd.DataFrame(array, index=x, columns=group_labels).plot.bar()
3051
+
3052
+
3053
+ An iterable of array-like: The iteration runs over the groups.
3054
+ Each individual array-like is the list of label values for that group.
3055
+ dataset_labels : array-like of str, optional
3056
+ The labels of the datasets.
3057
+ """
3058
+ if hasattr (heights , 'keys' ):
3059
+ if dataset_labels is not None :
3060
+ raise ValueError (
3061
+ "'dataset_labels' cannot be used if 'heights' are a mapping" )
3062
+ dataset_labels = heights .keys ()
3063
+ heights = heights .values ()
3064
+ elif hasattr (heights , 'shape' ):
3065
+ heights = heights .T
3066
+
3067
+ num_labels = len (x )
3068
+ num_datasets = len (heights )
3069
+
3070
+ for dataset in heights :
3071
+ assert len (dataset ) == num_labels
3072
+
3073
+ margin = 0.1
3074
+ bar_width = (1 - 2 * margin ) / num_datasets
3075
+ block_centers = np .arange (num_labels )
3076
+
3077
+ if dataset_labels is None :
3078
+ dataset_labels = [None ] * num_datasets
3079
+ else :
3080
+ assert len (dataset_labels ) == num_datasets
3081
+
3082
+ for i , (hs , dataset_label ) in enumerate (zip (heights , dataset_labels )):
3083
+ lefts = block_centers - 0.5 + margin + i * bar_width
3084
+ print (i , x , lefts , hs , dataset_label )
3085
+ self .bar (lefts , hs , width = bar_width , align = "edge" , label = dataset_label )
3086
+
3087
+ self .xaxis .set_ticks (block_centers , labels = x )
3088
+
3089
+ # TODO: does not return anything for now
3090
+
3003
3091
@_preprocess_data ()
3004
3092
def stem (self , * args , linefmt = None , markerfmt = None , basefmt = None , bottom = 0 ,
3005
3093
label = None , orientation = 'vertical' ):
0 commit comments