@@ -6462,23 +6462,52 @@ def _pcolorargs(self, funcname, *args, shading='auto', **kwargs):
64626462 # - reset shading if shading='auto' to flat or nearest
64636463 # depending on size;
64646464
6465+ # Check and normalize shading parameter:
6466+ if isinstance (shading , str ):
6467+ shading = shading .lower ()
6468+ shading_x = shading_y = shading
6469+ else :
6470+ try :
6471+ shading_x , shading_y = shading
6472+ if isinstance (shading_x , str ):
6473+ shading_x = shading_x .lower ()
6474+ if isinstance (shading_y , str ):
6475+ shading_y = shading_y .lower ()
6476+ except (ValueError , TypeError ) as e :
6477+ raise ValueError (
6478+ "shading must be a string or a 2-tuple of strings"
6479+ ) from e
6480+
64656481 _valid_shading = ['gouraud' , 'nearest' , 'flat' , 'auto' ]
6466- try :
6467- _api .check_in_list (_valid_shading , shading = shading )
6468- except ValueError :
6469- _api .warn_external (f"shading value '{ shading } ' not in list of "
6470- f"valid values { _valid_shading } . Setting "
6471- "shading='auto'." )
6472- shading = 'auto'
6482+ _api .check_in_list (_valid_shading , shading_x = shading_x )
6483+ _api .check_in_list (_valid_shading , shading_y = shading_y )
6484+
6485+ if (
6486+ (shading_x == 'gouraud' or shading_y == 'gouraud' )
6487+ and shading_x != shading_y
6488+ ):
6489+ raise ValueError (
6490+ "shading='gouraud' cannot be mixed with other shading types."
6491+ )
64736492
64746493 if len (args ) == 1 :
64756494 C = np .asanyarray (args [0 ])
64766495 nrows , ncols = C .shape [:2 ]
6477- if shading in ['gouraud' , 'nearest' ]:
6478- X , Y = np .meshgrid (np .arange (ncols ), np .arange (nrows ))
6496+
6497+ grid_shading_x = 'flat' if shading_x == 'auto' else shading_x
6498+ grid_shading_y = 'flat' if shading_y == 'auto' else shading_y
6499+
6500+ if grid_shading_x in ['gouraud' , 'nearest' ]:
6501+ x_grid = np .arange (ncols )
64796502 else :
6480- X , Y = np .meshgrid (np .arange (ncols + 1 ), np .arange (nrows + 1 ))
6481- shading = 'flat'
6503+ x_grid = np .arange (ncols + 1 )
6504+
6505+ if grid_shading_y in ['gouraud' , 'nearest' ]:
6506+ y_grid = np .arange (nrows )
6507+ else :
6508+ y_grid = np .arange (nrows + 1 )
6509+
6510+ X , Y = np .meshgrid (x_grid , y_grid )
64826511 elif len (args ) == 3 :
64836512 # Check x and y for bad data...
64846513 C = np .asanyarray (args [2 ])
@@ -6509,61 +6538,81 @@ def _pcolorargs(self, funcname, *args, shading='auto', **kwargs):
65096538 raise TypeError (f'Incompatible X, Y inputs to { funcname } ; '
65106539 f'see help({ funcname } )' )
65116540
6512- if shading == 'auto' :
6513- if ncols == Nx and nrows == Ny :
6514- shading = 'nearest'
6541+ if shading_x == 'auto' :
6542+ if ncols == Nx :
6543+ shading_x = 'nearest'
65156544 else :
6516- shading = 'flat'
6517-
6518- if shading == 'flat' :
6519- if (Nx , Ny ) != (ncols + 1 , nrows + 1 ):
6520- raise TypeError (f"Dimensions of C { C .shape } should"
6521- f" be one smaller than X({ Nx } ) and Y({ Ny } )"
6522- f" while using shading='flat'"
6523- f" see help({ funcname } )" )
6524- else : # ['nearest', 'gouraud']:
6545+ shading_x = 'flat'
6546+ if shading_y == 'auto' :
6547+ if nrows == Ny :
6548+ shading_y = 'nearest'
6549+ else :
6550+ shading_y = 'flat'
6551+
6552+ if shading_x == 'gouraud' :
65256553 if (Nx , Ny ) != (ncols , nrows ):
65266554 raise TypeError ('Dimensions of C %s are incompatible with'
65276555 ' X (%d) and/or Y (%d); see help(%s)' % (
65286556 C .shape , Nx , Ny , funcname ))
6529- if shading == 'nearest' :
6530- # grid is specified at the center, so define corners
6531- # at the midpoints between the grid centers and then use the
6532- # flat algorithm.
6533- def _interp_grid (X , require_monotonicity = False ):
6534- # helper for below. To ensure the cell edges are calculated
6535- # correctly, when expanding columns, the monotonicity of
6536- # X coords needs to be checked. When expanding rows, the
6537- # monotonicity of Y coords needs to be checked.
6538- if np .shape (X )[1 ] > 1 :
6539- dX = np .diff (X , axis = 1 ) * 0.5
6540- if (require_monotonicity and
6541- not (np .all (dX >= 0 ) or np .all (dX <= 0 ))):
6542- _api .warn_external (
6543- f"The input coordinates to { funcname } are "
6544- "interpreted as cell centers, but are not "
6545- "monotonically increasing or decreasing. "
6546- "This may lead to incorrectly calculated cell "
6547- "edges, in which case, please supply "
6548- f"explicit cell edges to { funcname } ." )
6549-
6550- hstack = np .ma .hstack if np .ma .isMA (X ) else np .hstack
6551- X = hstack ((X [:, [0 ]] - dX [:, [0 ]],
6552- X [:, :- 1 ] + dX ,
6553- X [:, [- 1 ]] + dX [:, [- 1 ]]))
6554- else :
6555- # This is just degenerate, but we can't reliably guess
6556- # a dX if there is just one value.
6557- X = np .hstack ((X , X ))
6558- return X
6559-
6560- if ncols == Nx :
6561- X = _interp_grid (X , require_monotonicity = True )
6562- Y = _interp_grid (Y )
6563- if nrows == Ny :
6564- X = _interp_grid (X .T ).T
6565- Y = _interp_grid (Y .T , require_monotonicity = True ).T
6566- shading = 'flat'
6557+ shading = 'gouraud'
6558+ else :
6559+ if shading_x == 'flat' and Nx != ncols + 1 :
6560+ raise TypeError (f"Dimensions of C { C .shape } should be one smaller than "
6561+ f"X ({ Nx } ) along the X-axis while using shading='flat'" )
6562+ if shading_x == 'nearest' and Nx != ncols :
6563+ raise TypeError (
6564+ f"Dimensions of C { C .shape } should be equal to "
6565+ f"X ({ Nx } ) along the X-axis while using "
6566+ "shading='nearest'"
6567+ )
6568+
6569+ if shading_y == 'flat' and Ny != nrows + 1 :
6570+ raise TypeError (f"Dimensions of C { C .shape } should be one smaller than "
6571+ f"Y ({ Ny } ) along the Y-axis while using shading='flat'" )
6572+ if shading_y == 'nearest' and Ny != nrows :
6573+ raise TypeError (
6574+ f"Dimensions of C { C .shape } should be equal to "
6575+ f"Y ({ Ny } ) along the Y-axis while using "
6576+ "shading='nearest'"
6577+ )
6578+
6579+ # grid is specified at the center, so define corners
6580+ # at the midpoints between the grid centers and then use the
6581+ # flat algorithm.
6582+ def _interp_grid (X , require_monotonicity = False ):
6583+ # helper for below. To ensure the cell edges are calculated
6584+ # correctly, when expanding columns, the monotonicity of
6585+ # X coords needs to be checked. When expanding rows, the
6586+ # monotonicity of Y coords needs to be checked.
6587+ if np .shape (X )[1 ] > 1 :
6588+ dX = np .diff (X , axis = 1 ) * 0.5
6589+ if (require_monotonicity and
6590+ not (np .all (dX >= 0 ) or np .all (dX <= 0 ))):
6591+ _api .warn_external (
6592+ f"The input coordinates to { funcname } are "
6593+ "interpreted as cell centers, but are not "
6594+ "monotonically increasing or decreasing. "
6595+ "This may lead to incorrectly calculated cell "
6596+ "edges, in which case, please supply "
6597+ f"explicit cell edges to { funcname } ." )
6598+
6599+ hstack = np .ma .hstack if np .ma .isMA (X ) else np .hstack
6600+ X = hstack ((X [:, [0 ]] - dX [:, [0 ]],
6601+ X [:, :- 1 ] + dX ,
6602+ X [:, [- 1 ]] + dX [:, [- 1 ]]))
6603+ else :
6604+ # This is just degenerate, but we can't reliably guess
6605+ # a dX if there is just one value.
6606+ X = np .hstack ((X , X ))
6607+ return X
6608+
6609+ if shading_x == 'nearest' :
6610+ X = _interp_grid (X , require_monotonicity = True )
6611+ Y = _interp_grid (Y )
6612+ if shading_y == 'nearest' :
6613+ X = _interp_grid (X .T ).T
6614+ Y = _interp_grid (Y .T , require_monotonicity = True ).T
6615+ shading = 'flat'
65676616
65686617 C = cbook .safe_masked_invalid (C , copy = True )
65696618 return X , Y , C , shading
@@ -6623,7 +6672,7 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None,
66236672 expanded as needed into the appropriate 2D arrays, making a
66246673 rectangular grid.
66256674
6626- shading : {'flat', 'nearest', 'auto'}, default: :rc:`pcolor.shading`
6675+ shading : {'flat', 'nearest', 'auto'} or 2-tuple , default: :rc:`pcolor.shading`
66276676 The fill style for the quadrilateral. Possible values:
66286677
66296678 - 'flat': A solid color is used for each quad. The color of the
@@ -6636,6 +6685,10 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None,
66366685 - 'auto': Choose 'flat' if dimensions of *X* and *Y* are one
66376686 larger than *C*. Choose 'nearest' if dimensions are the same.
66386687
6688+ Additionally, a 2-tuple of strings `(shading_x, shading_y)` can be
6689+ passed to specify different shading types for the X and Y axes
6690+ individually.
6691+
66396692 See :doc:`/gallery/images_contours_and_fields/pcolormesh_grids`
66406693 for more description.
66416694
@@ -6717,7 +6770,8 @@ def pcolor(self, *args, shading=None, alpha=None, norm=None, cmap=None,
67176770
67186771 if shading is None :
67196772 shading = mpl .rcParams ['pcolor.shading' ]
6720- shading = shading .lower ()
6773+ if isinstance (shading , str ):
6774+ shading = shading .lower ()
67216775 X , Y , C , shading = self ._pcolorargs ('pcolor' , * args , shading = shading ,
67226776 kwargs = kwargs )
67236777 linewidths = (0.25 ,)
@@ -6850,7 +6904,7 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
68506904 alpha : float, default: None
68516905 The alpha blending value, between 0 (transparent) and 1 (opaque).
68526906
6853- shading : {'flat', 'nearest', 'gouraud', 'auto'}, optional
6907+ shading : {'flat', 'nearest', 'gouraud', 'auto'} or 2-tuple , optional
68546908 The fill style for the quadrilateral; defaults to
68556909 :rc:`pcolor.shading`. Possible values:
68566910
@@ -6869,6 +6923,11 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
68696923 - 'auto': Choose 'flat' if dimensions of *X* and *Y* are one
68706924 larger than *C*. Choose 'nearest' if dimensions are the same.
68716925
6926+ Additionally, a 2-tuple of strings `(shading_x, shading_y)` can be
6927+ passed to specify different shading types for the X and Y axes
6928+ individually. Note that 'gouraud' cannot be mixed with other shading
6929+ types.
6930+
68726931 See :doc:`/gallery/images_contours_and_fields/pcolormesh_grids`
68736932 for more description.
68746933
@@ -6953,7 +7012,9 @@ def pcolormesh(self, *args, alpha=None, norm=None, cmap=None, vmin=None,
69537012 `~.Axes.pcolormesh`, which is not available with `~.Axes.pcolor`.
69547013
69557014 """
6956- shading = mpl ._val_or_rc (shading , 'pcolor.shading' ).lower ()
7015+ shading = mpl ._val_or_rc (shading , 'pcolor.shading' )
7016+ if isinstance (shading , str ):
7017+ shading = shading .lower ()
69577018 kwargs .setdefault ('edgecolors' , 'none' )
69587019
69597020 X , Y , C , shading = self ._pcolorargs ('pcolormesh' , * args ,
0 commit comments