339339docstring ._snippet_manager ['colors.from_list' ] = _from_list_docstring
340340
341341
342- def _clip_colors (colors , clip = True , gray = 0.2 , warn = False ):
342+ def _clip_colors (colors , clip = True , gray = 0.2 , warn_invalid = False ):
343343 """
344344 Clip impossible colors rendered in an HSL-to-RGB colorspace
345345 conversion. Used by `PerceptualColormap`.
@@ -349,13 +349,11 @@ def _clip_colors(colors, clip=True, gray=0.2, warn=False):
349349 colors : sequence of 3-tuple
350350 The RGB colors.
351351 clip : bool, optional
352- If `clip` is ``True`` (the default), RGB channel values >1 are
353- clipped to 1. Otherwise, the color is masked out as gray.
352+ If `clip` is ``True`` (the default), RGB channel values >1
353+ are clipped to 1. Otherwise, the color is masked out as gray.
354354 gray : float, optional
355- The identical RGB channel values (gray color) to be used if
356- `clip` is ``True``.
357- warn : bool, optional
358- Whether to issue warning when colors are clipped.
355+ The identical RGB channel values (gray color) to be used
356+ if `clip` is ``True``.
359357 """
360358 colors = np .asarray (colors )
361359 under = colors < 0
@@ -364,15 +362,15 @@ def _clip_colors(colors, clip=True, gray=0.2, warn=False):
364362 colors [under ], colors [over ] = 0 , 1
365363 else :
366364 colors [under | over ] = gray
367- if warn :
365+ if warn_invalid :
368366 msg = 'Clipped' if clip else 'Invalid'
369367 for i , name in enumerate ('rgb' ):
370368 if np .any (under [:, i ]) or np .any (over [:, i ]):
371369 warnings ._warn_proplot (f'{ msg } { name !r} channel.' )
372370 return colors
373371
374372
375- def _get_channel (color , channel , space = 'hcl' ):
373+ def _color_channel (color , channel , space = 'hcl' ):
376374 """
377375 Get the hue, saturation, or luminance channel value from the input color. The
378376 color name `color` can optionally be a string with the format ``'color+x'``
@@ -586,7 +584,7 @@ def _load_colors(path, warn_on_failure=True):
586584 If ``True``, issue a warning when loading fails instead of raising an error.
587585 """
588586 # Warn or raise error (matches Colormap._from_file behavior)
589- if not os .path .exists (path ):
587+ if not os .path .isfile (path ):
590588 message = f'Failed to load color data file { path !r} . File not found.'
591589 if warn_on_failure :
592590 warnings ._warn_proplot (message )
@@ -782,7 +780,7 @@ def _warn_or_raise(descrip, error=RuntimeError):
782780 warnings ._warn_proplot (prefix + ' ' + descrip )
783781 else :
784782 raise error (prefix + ' ' + descrip )
785- if not os .path .exists (path ):
783+ if not os .path .isfile (path ):
786784 return _warn_or_raise ('File not found.' , FileNotFoundError )
787785
788786 # Directly read segmentdata json file
@@ -1944,7 +1942,7 @@ def __init__(
19441942 for i , xyy in enumerate (array ):
19451943 xyy = list (xyy ) # make copy!
19461944 for j , y in enumerate (xyy [1 :]): # modify the y values
1947- xyy [j + 1 ] = _get_channel (y , key , space )
1945+ xyy [j + 1 ] = _color_channel (y , key , space )
19481946 data [key ][i ] = xyy
19491947 # Initialize
19501948 super ().__init__ (name , data , gamma = 1.0 , N = N , ** kwargs )
@@ -2425,10 +2423,10 @@ def __init__(
24252423 # Instead user-reversed levels will always get passed here just as
24262424 # they are passed to SegmentedNorm inside plot.py
24272425 levels , descending = _sanitize_levels (levels )
2426+ vcenter = getattr (norm , 'vcenter' , None )
24282427 vmin = norm .vmin = np .min (levels )
24292428 vmax = norm .vmax = np .max (levels )
24302429 bins , _ = _sanitize_levels (norm (levels ))
2431- vcenter = getattr (norm , 'vcenter' , None )
24322430 mids = np .zeros ((levels .size + 1 ,))
24332431 mids [1 :- 1 ] = 0.5 * (levels [1 :] + levels [:- 1 ])
24342432 mids [0 ], mids [- 1 ] = mids [1 ], mids [- 2 ]
@@ -2442,12 +2440,20 @@ def __init__(
24422440 # minimum 0 maximum 1, would mess up color distribution. However this is still
24432441 # not perfect... get asymmetric color intensity either side of central point.
24442442 # So we add special handling for diverging norms below to improve symmetry.
2445- if unique in ('min' , 'both' ):
2446- mids [0 ] += step * (mids [1 ] - mids [2 ])
2447- if unique in ('max' , 'both' ):
2448- mids [- 1 ] += step * (mids [- 2 ] - mids [- 3 ])
2449- mmin , mmax = np .min (mids ), np .max (mids )
2450- if vcenter is None :
2443+ if len (levels ) == 2 :
2444+ step = 0.5 # dummy step
2445+ mids [0 ] += step * (levels [0 ] - levels [1 ])
2446+ mids [- 1 ] += step * (levels [- 1 ] - levels [- 2 ])
2447+ else :
2448+ if unique in ('min' , 'both' ):
2449+ offset = mids [1 ] - mids [2 ]
2450+ mids [0 ] += step * offset
2451+ if unique in ('max' , 'both' ):
2452+ offset = mids [- 2 ] - mids [- 3 ]
2453+ mids [- 1 ] += step * offset
2454+ mmin = np .min (mids )
2455+ mmax = np .max (mids )
2456+ if vcenter is None : # not diverging norm or centered segmented norm
24512457 mids = _interpolate_scalar (mids , mmin , mmax , vmin , vmax )
24522458 else :
24532459 mask1 , mask2 = mids < vcenter , mids >= vcenter
0 commit comments