@@ -2152,7 +2152,7 @@ def _parse_cmap(
21522152 # WARNING: Previously 'colors' set the edgecolors. To avoid all-black
21532153 # colormap make sure to ignore 'colors' if 'cmap' was also passed.
21542154 # WARNING: Previously tried setting number of levels to len(colors), but this
2155- # makes single-level single-color contour plots, and since _parse_level_count is
2155+ # makes single-level single-color contour plots, and since _parse_level_num is
21562156 # only generates approximate level counts, the idea failed anyway. Users should
21572157 # pass their own levels to avoid truncation/cycling in these very special cases.
21582158 autodiverging = rc ['cmap.autodiverging' ]
@@ -2216,7 +2216,7 @@ def _parse_cmap(
22162216 if abs (np .sign (vmax ) - np .sign (vmin )) == 2 :
22172217 isdiverging = True
22182218 if discrete :
2219- levels , vmin , vmax , norm , norm_kw , kwargs = self ._parse_level_list (
2219+ levels , vmin , vmax , norm , norm_kw , kwargs = self ._parse_level_vals (
22202220 * args , vmin = vmin , vmax = vmax , norm = norm , norm_kw = norm_kw , extend = extend ,
22212221 min_levels = min_levels , skip_autolev = skip_autolev , ** kwargs
22222222 )
@@ -2250,7 +2250,7 @@ def _parse_cmap(
22502250 # Create the discrete normalizer
22512251 # Then finally warn and remove unused args
22522252 if levels is not None :
2253- norm , cmap , kwargs = self ._parse_discrete_norm (
2253+ norm , cmap , kwargs = self ._parse_level_norm (
22542254 levels , norm , cmap , extend = extend , min_levels = min_levels , ** kwargs
22552255 )
22562256 params = _pop_params (kwargs , * self ._level_parsers , ignore_internal = True )
@@ -2336,7 +2336,119 @@ def _parse_cycle(
23362336 else :
23372337 return kwargs
23382338
2339- def _parse_level_count (
2339+ def _parse_level_lim (
2340+ self , * args ,
2341+ vmin = None , vmax = None , robust = None , inbounds = None ,
2342+ negative = None , positive = None , symmetric = None , to_centers = False , ** kwargs
2343+ ):
2344+ """
2345+ Return a suitable vmin and vmax based on the input data.
2346+
2347+ Parameters
2348+ ----------
2349+ *args
2350+ The sample data.
2351+ vmin, vmax : float, optional
2352+ The user input minimum and maximum.
2353+ robust : bool, optional
2354+ Whether to limit the default range to exclude outliers.
2355+ inbounds : bool, optional
2356+ Whether to filter to in-bounds data.
2357+ negative, positive, symmetric : bool, optional
2358+ Whether limits should be negative, positive, or symmetric.
2359+ to_centers : bool, optional
2360+ Whether to convert coordinates to 'centers'.
2361+
2362+ Returns
2363+ -------
2364+ vmin, vmax : float
2365+ The minimum and maximum.
2366+ **kwargs
2367+ Unused arguemnts.
2368+ """
2369+ # Parse vmin and vmax
2370+ automin = vmin is None
2371+ automax = vmax is None
2372+ if not automin and not automax :
2373+ return vmin , vmax , kwargs
2374+
2375+ # Parse input args
2376+ inbounds = _not_none (inbounds , rc ['cmap.inbounds' ])
2377+ robust = _not_none (robust , rc ['cmap.robust' ], False )
2378+ robust = 96 if robust is True else 100 if robust is False else robust
2379+ robust = np .atleast_1d (robust )
2380+ if robust .size == 1 :
2381+ pmin , pmax = 50 + 0.5 * np .array ([- robust .item (), robust .item ()])
2382+ elif robust .size == 2 :
2383+ pmin , pmax = robust .flat # pull out of array
2384+ else :
2385+ raise ValueError (f'Unexpected robust={ robust !r} . Must be bool, float, or 2-tuple.' ) # noqa: E501
2386+
2387+ # Get sample data
2388+ # NOTE: Critical to use _to_numpy_array here because some
2389+ # commands are unstandardized.
2390+ # NOTE: Try to get reasonable *count* levels for hexbin/hist2d, but in general
2391+ # have no way to select nice ones a priori (why we disable discretenorm).
2392+ # NOTE: Currently we only ever use this function with *single* array input
2393+ # but in future could make this public as a way for users (me) to get
2394+ # automatic synced contours for a bunch of arrays in a grid.
2395+ vmins , vmaxs = [], []
2396+ if len (args ) > 2 :
2397+ x , y , * zs = args
2398+ else :
2399+ x , y , * zs = None , None , * args
2400+ for z in zs :
2401+ if z is None : # e.g. empty scatter color
2402+ continue
2403+ if z .ndim > 2 : # e.g. imshow data
2404+ continue
2405+ z = inputs ._to_numpy_array (z )
2406+ if inbounds and x is not None and y is not None : # ignore if None coords
2407+ z = self ._inbounds_vlim (x , y , z , to_centers = to_centers )
2408+ imin , imax = inputs ._safe_range (z , pmin , pmax )
2409+ if automin and imin is not None :
2410+ vmins .append (imin )
2411+ if automax and imax is not None :
2412+ vmaxs .append (imax )
2413+ if automin :
2414+ vmin = min (vmins , default = 0 )
2415+ if automax :
2416+ vmax = max (vmaxs , default = 1 )
2417+
2418+ # Apply modifications
2419+ # NOTE: This is also applied to manual input levels lists in _parse_level_vals
2420+ if negative :
2421+ if automax :
2422+ vmax = 0
2423+ else :
2424+ warnings ._warn_proplot (
2425+ f'Incompatible arguments vmax={ vmax !r} and negative=True. '
2426+ 'Ignoring the latter.'
2427+ )
2428+ if positive :
2429+ if automin :
2430+ vmin = 0
2431+ else :
2432+ warnings ._warn_proplot (
2433+ f'Incompatible arguments vmin={ vmin !r} and positive=True. '
2434+ 'Ignoring the latter.'
2435+ )
2436+ if symmetric :
2437+ if automin and not automax :
2438+ vmin = - vmax
2439+ elif automax and not automin :
2440+ vmax = - vmin
2441+ elif automin and automax :
2442+ vmin , vmax = - np .max (np .abs ((vmin , vmax ))), np .max (np .abs ((vmin , vmax )))
2443+ else :
2444+ warnings ._warn_proplot (
2445+ f'Incompatible arguments vmin={ vmin !r} , vmax={ vmax !r} , and '
2446+ 'symmetric=True. Ignoring the latter.'
2447+ )
2448+
2449+ return vmin , vmax , kwargs
2450+
2451+ def _parse_level_num (
23402452 self , * args , levels = None , locator = None , locator_kw = None , vmin = None , vmax = None ,
23412453 norm = None , norm_kw = None , extend = None , symmetric = None , ** kwargs
23422454 ):
@@ -2448,7 +2560,7 @@ def _parse_level_count(
24482560
24492561 return levels , kwargs
24502562
2451- def _parse_level_list (
2563+ def _parse_level_vals (
24522564 self , * args , N = None , levels = None , values = None , extend = None ,
24532565 positive = False , negative = False , nozero = False , norm = None , norm_kw = None ,
24542566 skip_autolev = False , min_levels = None , ** kwargs ,
@@ -2541,7 +2653,7 @@ def _sanitize_levels(key, array, minsize):
25412653 levels = _not_none (levels , rc ['cmap.levels' ])
25422654 else :
25432655 values = _sanitize_levels ('values' , values , 1 )
2544- kwargs ['discrete_ticks' ] = values # passed to _parse_discrete_norm
2656+ kwargs ['discrete_ticks' ] = values # passed to _parse_level_norm
25452657 if len (values ) == 1 :
25462658 levels = [values [0 ] - 1 , values [0 ] + 1 ] # weird but why not
25472659 elif norm is not None and norm not in ('segments' , 'segmented' ):
@@ -2569,11 +2681,11 @@ def _sanitize_levels(key, array, minsize):
25692681 # this function reverses them and adds special attribute to the normalizer.
25702682 # Then colorbar() reads this attr and flips the axis and the colormap direction
25712683 if np .iterable (levels ):
2572- pop = _pop_params (kwargs , self ._parse_level_count , ignore_internal = True )
2684+ pop = _pop_params (kwargs , self ._parse_level_num , ignore_internal = True )
25732685 if pop :
25742686 warnings ._warn_proplot (f'Ignoring unused keyword arg(s): { pop } ' )
25752687 elif not skip_autolev :
2576- levels , kwargs = self ._parse_level_count (
2688+ levels , kwargs = self ._parse_level_num (
25772689 * args , levels = levels , norm = norm , norm_kw = norm_kw , extend = extend ,
25782690 negative = negative , positive = positive , ** kwargs
25792691 )
@@ -2600,120 +2712,8 @@ def _sanitize_levels(key, array, minsize):
26002712
26012713 return levels , vmin , vmax , norm , norm_kw , kwargs
26022714
2603- def _parse_level_lim (
2604- self , * args ,
2605- vmin = None , vmax = None , robust = None , inbounds = None ,
2606- negative = None , positive = None , symmetric = None , to_centers = False , ** kwargs
2607- ):
2608- """
2609- Return a suitable vmin and vmax based on the input data.
2610-
2611- Parameters
2612- ----------
2613- *args
2614- The sample data.
2615- vmin, vmax : float, optional
2616- The user input minimum and maximum.
2617- robust : bool, optional
2618- Whether to limit the default range to exclude outliers.
2619- inbounds : bool, optional
2620- Whether to filter to in-bounds data.
2621- negative, positive, symmetric : bool, optional
2622- Whether limits should be negative, positive, or symmetric.
2623- to_centers : bool, optional
2624- Whether to convert coordinates to 'centers'.
2625-
2626- Returns
2627- -------
2628- vmin, vmax : float
2629- The minimum and maximum.
2630- **kwargs
2631- Unused arguemnts.
2632- """
2633- # Parse vmin and vmax
2634- automin = vmin is None
2635- automax = vmax is None
2636- if not automin and not automax :
2637- return vmin , vmax , kwargs
2638-
2639- # Parse input args
2640- inbounds = _not_none (inbounds , rc ['cmap.inbounds' ])
2641- robust = _not_none (robust , rc ['cmap.robust' ], False )
2642- robust = 96 if robust is True else 100 if robust is False else robust
2643- robust = np .atleast_1d (robust )
2644- if robust .size == 1 :
2645- pmin , pmax = 50 + 0.5 * np .array ([- robust .item (), robust .item ()])
2646- elif robust .size == 2 :
2647- pmin , pmax = robust .flat # pull out of array
2648- else :
2649- raise ValueError (f'Unexpected robust={ robust !r} . Must be bool, float, or 2-tuple.' ) # noqa: E501
2650-
2651- # Get sample data
2652- # NOTE: Critical to use _to_numpy_array here because some
2653- # commands are unstandardized.
2654- # NOTE: Try to get reasonable *count* levels for hexbin/hist2d, but in general
2655- # have no way to select nice ones a priori (why we disable discretenorm).
2656- # NOTE: Currently we only ever use this function with *single* array input
2657- # but in future could make this public as a way for users (me) to get
2658- # automatic synced contours for a bunch of arrays in a grid.
2659- vmins , vmaxs = [], []
2660- if len (args ) > 2 :
2661- x , y , * zs = args
2662- else :
2663- x , y , * zs = None , None , * args
2664- for z in zs :
2665- if z is None : # e.g. empty scatter color
2666- continue
2667- if z .ndim > 2 : # e.g. imshow data
2668- continue
2669- z = inputs ._to_numpy_array (z )
2670- if inbounds and x is not None and y is not None : # ignore if None coords
2671- z = self ._inbounds_vlim (x , y , z , to_centers = to_centers )
2672- imin , imax = inputs ._safe_range (z , pmin , pmax )
2673- if automin and imin is not None :
2674- vmins .append (imin )
2675- if automax and imax is not None :
2676- vmaxs .append (imax )
2677- if automin :
2678- vmin = min (vmins , default = 0 )
2679- if automax :
2680- vmax = max (vmaxs , default = 1 )
2681-
2682- # Apply modifications
2683- # NOTE: This is also applied to manual input levels lists in _parse_level_list
2684- if negative :
2685- if automax :
2686- vmax = 0
2687- else :
2688- warnings ._warn_proplot (
2689- f'Incompatible arguments vmax={ vmax !r} and negative=True. '
2690- 'Ignoring the latter.'
2691- )
2692- if positive :
2693- if automin :
2694- vmin = 0
2695- else :
2696- warnings ._warn_proplot (
2697- f'Incompatible arguments vmin={ vmin !r} and positive=True. '
2698- 'Ignoring the latter.'
2699- )
2700- if symmetric :
2701- if automin and not automax :
2702- vmin = - vmax
2703- elif automax and not automin :
2704- vmax = - vmin
2705- elif automin and automax :
2706- vmin , vmax = - np .max (np .abs ((vmin , vmax ))), np .max (np .abs ((vmin , vmax )))
2707- else :
2708- warnings ._warn_proplot (
2709- f'Incompatible arguments vmin={ vmin !r} , vmax={ vmax !r} , and '
2710- 'symmetric=True. Ignoring the latter.'
2711- )
2712-
2713- return vmin , vmax , kwargs
2714-
27152715 @staticmethod
2716- def _parse_discrete_norm (
2716+ def _parse_level_norm (
27172717 levels , norm , cmap , * , extend = None , min_levels = None ,
27182718 discrete_ticks = None , discrete_labels = None , ** kwargs
27192719 ):
@@ -2748,7 +2748,7 @@ def _parse_discrete_norm(
27482748 Unused arguments.
27492749 """
27502750 # Reverse the colormap if input levels or values were descending
2751- # See _parse_level_list for details
2751+ # See _parse_level_vals for details
27522752 min_levels = _not_none (min_levels , 2 ) # 1 for contour plots
27532753 unique = extend = _not_none (extend , 'neither' )
27542754 under = cmap ._rgba_under
@@ -3806,8 +3806,8 @@ def hexbin(self, x, y, weights, **kwargs):
38063806 %(plot.hexbin)s
38073807 """
38083808 # WARNING: Cannot use automatic level generation here until counts are
3809- # estimated. Inside _parse_level_list if no manual levels were provided then
3810- # _parse_level_count is skipped and args like levels=10 or locator=5 are ignored
3809+ # estimated. Inside _parse_level_vals if no manual levels were provided then
3810+ # _parse_level_num is skipped and args like levels=10 or locator=5 are ignored
38113811 x , y , kw = self ._parse_1d_plot (x , y , autovalues = True , ** kwargs )
38123812 kw .update (_pop_props (kw , 'collection' )) # takes LineCollection props
38133813 kw = self ._parse_cmap (x , y , y , skip_autolev = True , default_discrete = False , ** kw )
@@ -4200,7 +4200,7 @@ def _iter_arg_cols(self, *args, label=None, labels=None, values=None, **kwargs):
42004200 yield (i , n , * a , kw )
42014201
42024202 # Related parsing functions for warnings
4203- _level_parsers = (_parse_level_list , _parse_level_count , _parse_level_lim )
4203+ _level_parsers = (_parse_level_vals , _parse_level_num , _parse_level_lim )
42044204
42054205 # Rename the shorthands
42064206 boxes = warnings ._rename_objs ('0.8.0' , boxes = box )
0 commit comments