@@ -262,8 +262,8 @@ def _axis_labels_title(data, axis=None, units=True):
262
262
263
263
def standardize_1d (self , func , * args , ** kwargs ):
264
264
"""
265
- Interprets positional arguments for the "1d" plotting methods
266
- %(methods)s . This also optionally modifies the x axis label, y axis label,
265
+ Interpret positional arguments for the "1d" plotting methods so usage is
266
+ consistent . This also optionally modifies the x axis label, y axis label,
267
267
title, and axis ticks if a `~xarray.DataArray`, `~pandas.DataFrame`, or
268
268
`~pandas.Series` is passed.
269
269
@@ -280,6 +280,10 @@ def standardize_1d(self, func, *args, **kwargs):
280
280
See also
281
281
--------
282
282
cycle_changer
283
+
284
+ Note
285
+ ----
286
+ This function wraps the 1d plotting methods: %(methods)s.
283
287
"""
284
288
# Sanitize input
285
289
# TODO: Add exceptions for methods other than 'hist'?
@@ -311,8 +315,10 @@ def standardize_1d(self, func, *args, **kwargs):
311
315
# Auto x coords
312
316
y = ys [0 ] # test the first y input
313
317
if x is None :
314
- axis = 1 if (name in ('hist' , 'boxplot' , 'violinplot' ) or any (
315
- kwargs .get (s , None ) for s in ('means' , 'medians' ))) else 0
318
+ axis = int (
319
+ name in ('hist' , 'boxplot' , 'violinplot' )
320
+ or any (kwargs .get (s , None ) for s in ('means' , 'medians' ))
321
+ )
316
322
x , _ = _axis_labels_title (y , axis = axis )
317
323
x = _to_array (x )
318
324
if x .ndim != 1 :
@@ -452,8 +458,8 @@ def _standardize_latlon(x, y):
452
458
453
459
def standardize_2d (self , func , * args , order = 'C' , globe = False , ** kwargs ):
454
460
"""
455
- Interprets positional arguments for the "2d" plotting methods
456
- %(methods)s . This also optionally modifies the x axis label, y axis label,
461
+ Interpret positional arguments for the "2d" plotting methods so usage is
462
+ consistent . This also optionally modifies the x axis label, y axis label,
457
463
title, and axis ticks if a `~xarray.DataArray`, `~pandas.DataFrame`, or
458
464
`~pandas.Series` is passed.
459
465
@@ -484,6 +490,10 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
484
490
See also
485
491
--------
486
492
cmap_changer
493
+
494
+ Note
495
+ ----
496
+ This function wraps the 2d plotting methods: %(methods)s.
487
497
"""
488
498
# Sanitize input
489
499
name = func .__name__
@@ -587,10 +597,7 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
587
597
f'Input arrays must be 2d, instead got shape { Z .shape } .'
588
598
)
589
599
elif Z .shape [1 ] == xlen and Z .shape [0 ] == ylen :
590
- if all (
591
- z .ndim == 1 and z .size > 1
592
- and _is_number (z ) for z in (x , y )
593
- ):
600
+ if all (z .ndim == 1 and z .size > 1 and _is_number (z ) for z in (x , y )):
594
601
x = edges (x )
595
602
y = edges (y )
596
603
else :
@@ -610,6 +617,7 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
610
617
f'Z centers { Z .shape } or '
611
618
f'Z borders { tuple (i + 1 for i in Z .shape )} .'
612
619
)
620
+
613
621
# Optionally re-order
614
622
# TODO: Double check this
615
623
if order == 'F' :
@@ -632,33 +640,27 @@ def standardize_2d(self, func, *args, order='C', globe=False, **kwargs):
632
640
f'Input arrays must be 2d, instead got shape { Z .shape } .'
633
641
)
634
642
elif Z .shape [1 ] == xlen - 1 and Z .shape [0 ] == ylen - 1 :
635
- if all (
636
- z .ndim == 1 and z .size > 1
637
- and _is_number (z ) for z in (x , y )
638
- ):
643
+ if all (z .ndim == 1 and z .size > 1 and _is_number (z ) for z in (x , y )):
639
644
x = (x [1 :] + x [:- 1 ]) / 2
640
645
y = (y [1 :] + y [:- 1 ]) / 2
641
646
else :
642
647
if (
643
648
x .ndim == 2 and x .shape [0 ] > 1 and x .shape [1 ] > 1
644
649
and _is_number (x )
645
650
):
646
- x = 0.25 * (
647
- x [:- 1 , :- 1 ] + x [:- 1 , 1 :] + x [1 :, :- 1 ] + x [1 :, 1 :]
648
- )
651
+ x = 0.25 * (x [:- 1 , :- 1 ] + x [:- 1 , 1 :] + x [1 :, :- 1 ] + x [1 :, 1 :])
649
652
if (
650
653
y .ndim == 2 and y .shape [0 ] > 1 and y .shape [1 ] > 1
651
654
and _is_number (y )
652
655
):
653
- y = 0.25 * (
654
- y [:- 1 , :- 1 ] + y [:- 1 , 1 :] + y [1 :, :- 1 ] + y [1 :, 1 :]
655
- )
656
+ y = 0.25 * (y [:- 1 , :- 1 ] + y [:- 1 , 1 :] + y [1 :, :- 1 ] + y [1 :, 1 :])
656
657
elif Z .shape [1 ] != xlen or Z .shape [0 ] != ylen :
657
658
raise ValueError (
658
659
f'Input shapes x { x .shape } and y { y .shape } '
659
660
f'must match Z centers { Z .shape } '
660
661
f'or Z borders { tuple (i + 1 for i in Z .shape )} .'
661
662
)
663
+
662
664
# Optionally re-order
663
665
# TODO: Double check this
664
666
if order == 'F' :
@@ -1819,13 +1821,31 @@ def cycle_changer(
1819
1821
key = 'edgecolors'
1820
1822
kw [key ] = value
1821
1823
1822
- # Get x coordinates
1823
- x_col , y_first = x , ys [0 ] # samples
1824
+ # Add x coordinates as pi chart labels by default
1824
1825
if name in ('pie' ,):
1825
- kw ['labels' ] = _not_none (labels , x_col ) # TODO: move to pie wrapper?
1826
+ kw ['labels' ] = _not_none (labels , x ) # TODO: move to pie wrapper?
1827
+
1828
+ # Step size for grouped bar plots
1829
+ # WARNING: This will fail for non-numeric non-datetime64 singleton
1830
+ # datatypes but this is good enough for vast majority of most cases.
1831
+ x_test = np .atleast_1d (_to_ndarray (x ))
1832
+ if len (x_test ) >= 2 :
1833
+ x_step = x_test [1 :] - x_test [:- 1 ]
1834
+ x_step = np .concatenate ((x_step , x_step [- 1 :]))
1835
+ elif x_test .dtype == np .datetime64 :
1836
+ x_step = np .timedelta64 (1 , 'D' )
1837
+ else :
1838
+ x_step = np .array (0.5 )
1839
+ if np .issubdtype (x_test .dtype , np .datetime64 ):
1840
+ x_step = x_step .astype ('timedelta64[ns]' ) # avoid int timedelta truncation
1841
+
1842
+ # Get x coordinates for bar plot
1843
+ x_col , y_first = x , ys [0 ] # samples
1826
1844
if name in ('bar' ,): # adjust
1827
1845
if not stacked :
1828
- x_col = x + (i - ncols / 2 + 0.5 ) * width / ncols
1846
+ scale = i - 0.5 * (ncols - 1 ) # offset from true coordinate
1847
+ scale = width * scale / ncols
1848
+ x_col = x + x_step * scale
1829
1849
elif stacked and y_first .ndim > 1 :
1830
1850
key = 'x' if barh else 'bottom'
1831
1851
kw [key ] = _to_indexer (y_first )[:, :i ].sum (axis = 1 )
0 commit comments