@@ -2385,7 +2385,13 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center",
23852385
23862386 self ._request_autoscale_view ()
23872387
2388- bar_container = BarContainer (patches , errorbar , label = label )
2388+ if orientation == 'vertical' :
2389+ datavalues = height
2390+ elif orientation == 'horizontal' :
2391+ datavalues = width
2392+
2393+ bar_container = BarContainer (patches , errorbar , datavalues = datavalues ,
2394+ orientation = orientation , label = label )
23892395 self .add_container (bar_container )
23902396
23912397 if tick_labels is not None :
@@ -2501,6 +2507,132 @@ def barh(self, y, width, height=0.8, left=None, *, align="center",
25012507 align = align , ** kwargs )
25022508 return patches
25032509
2510+ def bar_label (self , container , labels = None , * , fmt = "%g" , label_type = "edge" ,
2511+ padding = 0 , ** kwargs ):
2512+ """
2513+ Label a bar plot.
2514+
2515+ Adds labels to bars in the given `.BarContainer`.
2516+ You may need to adjust the axis limits to fit the labels.
2517+
2518+ Parameters
2519+ ----------
2520+ container : `.BarContainer`
2521+ Container with all the bars and optionally errorbars, likely
2522+ returned from `.bar` or `.barh`.
2523+
2524+ labels : array-like, optional
2525+ A list of label texts, that should be displayed. If not given, the
2526+ label texts will be the data values formatted with *fmt*.
2527+
2528+ fmt : str, default: '%g'
2529+ A format string for the label.
2530+
2531+ label_type : {'edge', 'center'}, default: 'edge'
2532+ The label type. Possible values:
2533+
2534+ - 'edge': label placed at the end-point of the bar segment, and the
2535+ value displayed will be the position of that end-point.
2536+ - 'center': label placed in the center of the bar segment, and the
2537+ value displayed will be the length of that segment.
2538+ (useful for stacked bars, i.e.
2539+ :doc:`/gallery/lines_bars_and_markers/bar_label_demo`)
2540+
2541+ padding : float, default: 0
2542+ Distance of label from the end of the bar.
2543+
2544+ **kwargs
2545+ Any remaining keyword arguments are passed through to
2546+ `.Axes.annotate`.
2547+
2548+ Returns
2549+ -------
2550+ list of `.Text`
2551+ A list of `.Text` instances for the labels.
2552+ """
2553+
2554+ # want to know whether to put label on positive or negative direction
2555+ # cannot use np.sign here because it will return 0 if x == 0
2556+ def sign (x ):
2557+ return 1 if x >= 0 else - 1
2558+
2559+ _api .check_in_list (['edge' , 'center' ], label_type = label_type )
2560+
2561+ bars = container .patches
2562+ errorbar = container .errorbar
2563+ datavalues = container .datavalues
2564+ orientation = container .orientation
2565+
2566+ if errorbar :
2567+ # check "ErrorbarContainer" for the definition of these elements
2568+ lines = errorbar .lines # attribute of "ErrorbarContainer" (tuple)
2569+ barlinecols = lines [2 ] # 0: data_line, 1: caplines, 2: barlinecols
2570+ barlinecol = barlinecols [0 ] # the "LineCollection" of error bars
2571+ errs = barlinecol .get_segments ()
2572+ else :
2573+ errs = []
2574+
2575+ if labels is None :
2576+ labels = []
2577+
2578+ annotations = []
2579+
2580+ for bar , err , dat , lbl in itertools .zip_longest (
2581+ bars , errs , datavalues , labels
2582+ ):
2583+ (x0 , y0 ), (x1 , y1 ) = bar .get_bbox ().get_points ()
2584+ xc , yc = (x0 + x1 ) / 2 , (y0 + y1 ) / 2
2585+
2586+ if orientation == "vertical" :
2587+ extrema = max (y0 , y1 ) if dat >= 0 else min (y0 , y1 )
2588+ length = abs (y0 - y1 )
2589+ elif orientation == "horizontal" :
2590+ extrema = max (x0 , x1 ) if dat >= 0 else min (x0 , x1 )
2591+ length = abs (x0 - x1 )
2592+
2593+ if err is None :
2594+ endpt = extrema
2595+ elif orientation == "vertical" :
2596+ endpt = err [:, 1 ].max () if dat >= 0 else err [:, 1 ].min ()
2597+ elif orientation == "horizontal" :
2598+ endpt = err [:, 0 ].max () if dat >= 0 else err [:, 0 ].min ()
2599+
2600+ if label_type == "center" :
2601+ value = sign (dat ) * length
2602+ elif label_type == "edge" :
2603+ value = extrema
2604+
2605+ if label_type == "center" :
2606+ xy = xc , yc
2607+ elif label_type == "edge" and orientation == "vertical" :
2608+ xy = xc , endpt
2609+ elif label_type == "edge" and orientation == "horizontal" :
2610+ xy = endpt , yc
2611+
2612+ if orientation == "vertical" :
2613+ xytext = 0 , sign (dat ) * padding
2614+ else :
2615+ xytext = sign (dat ) * padding , 0
2616+
2617+ if label_type == "center" :
2618+ ha , va = "center" , "center"
2619+ elif label_type == "edge" :
2620+ if orientation == "vertical" and dat >= 0 :
2621+ ha , va = "center" , "bottom"
2622+ elif orientation == "vertical" and dat < 0 :
2623+ ha , va = "center" , "top"
2624+ elif orientation == "horizontal" and dat >= 0 :
2625+ ha , va = "left" , "center"
2626+ elif orientation == "horizontal" and dat < 0 :
2627+ ha , va = "right" , "center"
2628+
2629+ annotation = self .annotate (fmt % value if lbl is None else lbl ,
2630+ xy , xytext , textcoords = "offset points" ,
2631+ ha = ha , va = va , ** kwargs )
2632+ annotations .append (annotation )
2633+
2634+ return annotations
2635+
25042636 @_preprocess_data ()
25052637 @docstring .dedent_interpd
25062638 def broken_barh (self , xranges , yrange , ** kwargs ):
0 commit comments