@@ -1377,7 +1377,8 @@ def hist_wrapper(self, func, x, bins=None, **kwargs):
13771377def bar_wrapper (
13781378 self , func , x = None , height = None , width = 0.8 , bottom = None , * , left = None ,
13791379 vert = None , orientation = 'vertical' , stacked = False ,
1380- lw = None , linewidth = 0.7 , edgecolor = 'k' ,
1380+ lw = None , linewidth = 0.7 , edgecolor = 'black' ,
1381+ negpos = False , negcolor = None , poscolor = None ,
13811382 ** kwargs
13821383):
13831384 """
@@ -1396,49 +1397,69 @@ def bar_wrapper(
13961397 # TODO: Stacked feature is implemented in `cycle_changer`, but makes more
13971398 # sense do document here; figure out way to move it here?
13981399 if left is not None :
1399- warnings ._warn_proplot (
1400- 'The "left" keyword with bar() is deprecated. Use "x" instead.'
1401- )
1400+ warnings ._warn_proplot ('bar() keyword "left" is deprecated. Use "x" instead.' )
14021401 x = left
14031402 if x is None and height is None :
1404- raise ValueError (
1405- 'bar() requires at least 1 positional argument, got 0.'
1406- )
1403+ raise ValueError ('bar() requires at least 1 positional argument, got 0.' )
14071404 elif height is None :
14081405 x , height = None , x
1406+ args = (x , height )
1407+ linewidth = _not_none (lw = lw , linewidth = linewidth )
1408+ kwargs .update ({
1409+ 'width' : width , 'bottom' : bottom , 'stacked' : stacked ,
1410+ 'orientation' : orientation , 'linewidth' : linewidth , 'edgecolor' : edgecolor ,
1411+ })
14091412
14101413 # Call func
1411- # TODO : This *must* also be wrapped by cycle_changer, which ultimately
1414+ # NOTE : This *must* also be wrapped by cycle_changer, which ultimately
14121415 # permutes back the x/bottom args for horizontal bars! Need to clean up.
1413- lw = _not_none (lw = lw , linewidth = linewidth )
1414- return func (
1415- self , x , height , width = width , bottom = bottom ,
1416- linewidth = lw , edgecolor = edgecolor ,
1417- stacked = stacked , orientation = orientation ,
1418- ** kwargs
1419- )
1416+ if negpos :
1417+ # Draw negative and positive bars
1418+ # NOTE: cycle_changer makes bar widths *relative* to step size between
1419+ # x coordinates to cannot just omit data. Instead make some height nan.
1420+ message = 'bar() argument {}={!r} is incompatible with negpos=True. Ignoring.'
1421+ stacked = kwargs .pop ('stacked' , None )
1422+ if stacked :
1423+ warnings ._warn_proplot (message .format ('stacked' , stacked ))
1424+ height = np .asarray (height )
1425+ if height .ndim > 1 :
1426+ raise ValueError ('bar() heights with negpos=True must be 1D.' )
1427+ height1 = height .copy ().astype (np .float64 )
1428+ height1 [height >= 0 ] = np .nan
1429+ height2 = height .copy ().astype (np .float64 )
1430+ height2 [height < 0 ] = np .nan
1431+ negcolor = _not_none (negcolor , rc ['negcolor' ])
1432+ poscolor = _not_none (poscolor , rc ['poscolor' ])
1433+ obj1 = func (self , x , height1 , ** {'color' : negcolor , ** kwargs })
1434+ obj2 = func (self , x , height2 , ** {'color' : poscolor , ** kwargs })
1435+ result = (obj1 , obj2 )
1436+ else :
1437+ # Draw simple bars
1438+ result = func (self , * args , ** kwargs )
1439+ return result
14201440
14211441
1422- @docstring .add_snippets # noqa: U100
1442+ @docstring .add_snippets
14231443def barh_wrapper (
1424- self , func , y = None , width = None , height = 0.8 , left = None , ** kwargs
1444+ self , func , y = None , right = None , width = None , left = None , height = None , ** kwargs
14251445):
14261446 """
14271447 %(axes.barh)s
14281448 """
14291449 # Converts y-->bottom, left-->x, width-->height, height-->width.
14301450 # Convert back to (x, bottom, width, height) so we can pass stuff
14311451 # through cycle_changer.
1452+ # NOTE: ProPlot calls second positional argument 'right' so that 'width'
1453+ # means the width of *bars*.
14321454 # NOTE: You *must* do juggling of barh keyword order --> bar keyword order
14331455 # --> barh keyword order, because horizontal hist passes arguments to bar
14341456 # directly and will not use a 'barh' method with overridden argument order!
14351457 func # avoid U100 error
1458+ height = _not_none (height = height , width = width , default = 0.8 )
14361459 kwargs .setdefault ('orientation' , 'horizontal' )
14371460 if y is None and width is None :
1438- raise ValueError (
1439- 'barh() requires at least 1 positional argument, got 0.'
1440- )
1441- return self .bar (x = left , height = height , width = width , bottom = y , ** kwargs )
1461+ raise ValueError ('barh() requires at least 1 positional argument, got 0.' )
1462+ return self .bar (x = left , width = right , height = height , bottom = y , ** kwargs )
14421463
14431464
14441465def boxplot_wrapper (
0 commit comments