3939]
4040
4141# Colormap stuff
42- CMAPS_CATEGORIES = {
42+ CMAPS_TABLE = {
4343 # Assorted origin, but these belong together
4444 'Grayscale' : (
4545 'Grays' , 'Mono' , 'GrayCycle' ,
124124 'gist_earth' , 'gist_gray' , 'gist_heat' , 'gist_ncar' ,
125125 'gist_rainbow' , 'gist_stern' , 'gist_yarg' ,
126126 ),
127- 'Miscellaneous ' : (
127+ 'Other ' : (
128128 'binary' , 'bwr' , 'brg' , # appear to be custom matplotlib
129129 'cubehelix' , 'wistia' , 'CMRmap' , # individually released
130130 'seismic' , 'terrain' , 'nipy_spectral' , # origin ambiguous
131- ),
131+ 'tab10' , 'tab20' , 'tab20b' , 'tab20c' , # merged colormap cycles
132+ )
132133}
133134CMAPS_DELETE = (
134135 'binary' , 'gist_yarg' , 'gist_gray' , 'gray' , 'bone' , 'pink' ,
@@ -3116,8 +3117,54 @@ def register_fonts():
31163117 fonts [:] = [* fonts_proplot , * fonts_system ]
31173118
31183119
3119- def show_channels (* args , N = 100 , rgb = True , saturation = True ,
3120- minhue = 0 , maxsat = 1000 , axwidth = None , width = 100 ):
3120+ def _draw_bars (cmapdict , length = 4.0 , width = 0.2 ):
3121+ """
3122+ Draw colorbars for "colormaps" and "color cycles". This is called by
3123+ `show_cycles` and `show_cmaps`.
3124+ """
3125+ # Figure
3126+ from . import subplots
3127+ naxs = len (cmapdict ) + sum (map (len , cmapdict .values ()))
3128+ fig , axs = subplots (
3129+ nrows = naxs , axwidth = length , axheight = width ,
3130+ share = 0 , hspace = 0.03 ,
3131+ )
3132+ iax = - 1
3133+ nheads = nbars = 0 # for deciding which axes to plot in
3134+ a = np .linspace (0 , 1 , 257 ).reshape (1 , - 1 )
3135+ a = np .vstack ((a , a ))
3136+ for cat , names in cmapdict .items ():
3137+ if not names :
3138+ continue
3139+ nheads += 1
3140+ for imap , name in enumerate (names ):
3141+ iax += 1
3142+ if imap + nheads + nbars > naxs :
3143+ break
3144+ ax = axs [iax ]
3145+ if imap == 0 : # allocate this axes for title
3146+ iax += 1
3147+ ax .set_visible (False )
3148+ ax = axs [iax ]
3149+ cmap = mcm .cmap_d [name ]
3150+ ax .imshow (
3151+ a , cmap = name , origin = 'lower' , aspect = 'auto' ,
3152+ levels = cmap .N
3153+ )
3154+ ax .format (
3155+ ylabel = name ,
3156+ ylabel_kw = {'rotation' : 0 , 'ha' : 'right' , 'va' : 'center' },
3157+ xticks = 'none' , yticks = 'none' , # no ticks
3158+ xloc = 'neither' , yloc = 'neither' , # no spines
3159+ title = (cat if imap == 0 else None )
3160+ )
3161+ nbars += len (names )
3162+
3163+
3164+ def show_channels (
3165+ * args , N = 100 , rgb = True , saturation = True , minhue = 0 ,
3166+ maxsat = 500 , width = 100 , axwidth = 1.7
3167+ ):
31213168 """
31223169 Show how arbitrary colormap(s) vary with respect to the hue, chroma,
31233170 luminance, HSL saturation, and HPL saturation channels, and optionally
@@ -3149,12 +3196,12 @@ def show_channels(*args, N=100, rgb=True, saturation=True,
31493196 Returns
31503197 -------
31513198 `~proplot.subplots.Figure`
3152- The figure instance .
3153- """ # noqa
3199+ The figure.
3200+ """
31543201 # Figure and plot
31553202 from . import subplots
31563203 if not args :
3157- args = ( rcParams [ 'image.cmap' ], )
3204+ raise ValueError ( f'At least one positional argument required.' )
31583205 array = [[1 , 1 , 2 , 2 , 3 , 3 ]]
31593206 labels = ('Hue' , 'Chroma' , 'Luminance' )
31603207 if saturation :
@@ -3165,7 +3212,7 @@ def show_channels(*args, N=100, rgb=True, saturation=True,
31653212 labels += ('Red' , 'Green' , 'Blue' )
31663213 fig , axs = subplots (
31673214 array = array , span = False , share = 1 ,
3168- aspect = 1 , axwidth = axwidth , axpad = '1em' ,
3215+ axwidth = axwidth , axpad = '1em' ,
31693216 )
31703217 # Iterate through colormaps
31713218 mc , ms , mp = 0 , 0 , 0
@@ -3260,7 +3307,7 @@ def show_colorspaces(luminance=None, saturation=None, hue=None, axwidth=2):
32603307 Returns
32613308 -------
32623309 `~proplot.subplots.Figure`
3263- The figure instance .
3310+ The figure.
32643311 """
32653312 # Get colorspace properties
32663313 hues = np .linspace (0 , 360 , 361 )
@@ -3319,14 +3366,14 @@ def show_colorspaces(luminance=None, saturation=None, hue=None, axwidth=2):
33193366 return fig
33203367
33213368
3322- def show_colors (nbreak = 17 , minsat = 20 ):
3369+ def show_colors (nhues = 17 , minsat = 20 ):
33233370 """
3324- Visualize the registered color names in two figures . Adapted from
3325- `this example <https://matplotlib.org/examples/color/named_colors.html>`_ .
3371+ Generate tables of the registered color names. Adapted from
3372+ `this example <https://matplotlib.org/examples/color/named_colors.html>`__ .
33263373
33273374 Parameters
33283375 ----------
3329- nbreak : int, optional
3376+ nhues : int, optional
33303377 The number of breaks between hues for grouping "like colors" in the
33313378 color table.
33323379 minsat : float, optional
@@ -3336,16 +3383,16 @@ def show_colors(nbreak=17, minsat=20):
33363383 Returns
33373384 -------
33383385 figs : list of `~proplot.subplots.Figure`
3339- The figure instances .
3386+ The figure.
33403387 """
33413388 # Test used to "categories" colors
3342- breakpoints = np .linspace (0 , 360 , nbreak )
3389+ breakpoints = np .linspace (0 , 360 , nhues )
33433390 def _color_filter (i , hcl ): # noqa: E306
33443391 gray = hcl [1 ] <= minsat
33453392 if i == 0 :
33463393 return gray
33473394 color = breakpoints [i - 1 ] <= hcl [0 ] < breakpoints [i ]
3348- if i == nbreak - 1 :
3395+ if i == nhues - 1 :
33493396 color = color or color == breakpoints [i ] # endpoint inclusive
33503397 return not gray and color
33513398
@@ -3375,8 +3422,6 @@ def _color_filter(i, hcl): # noqa: E306
33753422 nrows = nrows * 2
33763423 ncols = (ncols + 1 ) // 2
33773424 names .resize ((ncols , nrows ))
3378- names = names .tolist ()
3379- # names = names.reshape((ncols, nrows)).tolist()
33803425
33813426 # Get colors in perceptally uniform space, then group based on hue
33823427 # thresholds
@@ -3393,7 +3438,7 @@ def _color_filter(i, hcl): # noqa: E306
33933438 [pair for pair in hclpairs if _color_filter (i , pair [1 ])],
33943439 key = lambda x : x [1 ][2 ]
33953440 )
3396- for i in range (nbreak )
3441+ for i in range (nhues )
33973442 ]
33983443 names = np .array ([
33993444 name for ipairs in hclpairs for name , _ in ipairs
@@ -3434,158 +3479,94 @@ def _color_filter(i, hcl): # noqa: E306
34343479 return figs
34353480
34363481
3437- def show_cmaps (* args , N = 256 , length = 4.0 , width = 0.2 , unknown = 'User' ):
3482+ def show_cmaps (* args , N = None , unknown = 'User' , ** kwargs ):
34383483 """
3439- Visualize all registered colormaps, or the list of colormap names if
3440- positional arguments are passed. Adapted from `this example \
3484+ Generate a table of the registered colormaps or the input colormaps.
3485+ Adapted from `this example \
34413486 <http://matplotlib.org/examples/color/colormaps_reference.html>`__.
34423487
34433488 Parameters
34443489 ----------
34453490 *args : colormap-spec, optional
3446- Positional arguments are colormap names or objects. Default is
3447- all of the registered colormaps.
3491+ Colormap names or objects.
34483492 N : int, optional
3449- The number of levels in each colorbar.
3493+ The number of levels in each colorbar. Default is
3494+ :rc:`image.lut`.
3495+ unknown : str, optional
3496+ Category name for colormaps that are unknown to ProPlot. The
3497+ default is ``'User'``.
34503498 length : float or str, optional
3451- The length of each colorbar . Units are interpreted by
3499+ The length of the colorbars . Units are interpreted by
34523500 `~proplot.utils.units`.
34533501 width : float or str, optional
3454- The width of each colorbar . Units are interpreted by
3502+ The width of the colorbars . Units are interpreted by
34553503 `~proplot.utils.units`.
3456- unknown : str, optional
3457- Category name for colormaps that are unknown to ProPlot. The
3458- default is ``'User'``.
34593504
34603505 Returns
34613506 -------
34623507 `~proplot.subplots.Figure`
3463- The figure instance .
3508+ The figure.
34643509 """
34653510 # Have colormaps separated into categories
3511+ N = _notNone (N , rcParams ['image.lut' ])
34663512 if args :
3467- imaps = [Colormap (cmap , N = N ).name for cmap in args ]
3513+ names = [Colormap (cmap , N = N ).name for cmap in args ]
34683514 else :
3469- imaps = [
3470- name for name in mcm .cmap_d .keys () if name not in ('vega' , 'greys' )
3471- and name [0 ] != '_'
3472- and isinstance (mcm .cmap_d [name ], LinearSegmentedColormap )
3515+ names = [
3516+ name for name in mcm .cmap_d .keys () if
3517+ isinstance (mcm .cmap_d [name ], LinearSegmentedColormap )
34733518 ]
34743519
34753520 # Get dictionary of registered colormaps and their categories
3476- imaps = [name .lower () for name in imaps ]
3477- cats = {cat : names for cat , names in CMAPS_CATEGORIES .items ()}
3478- cats_plot = {cat : [name for name in names if name .lower () in imaps ]
3479- for cat , names in cats .items ()}
3480- # Distinguish known from unknown (i.e. user) maps, add as a new category
3481- imaps_known = [name .lower () for cat , names in cats .items ()
3482- for name in names if name .lower () in imaps ]
3483- imaps_unknown = [name for name in imaps if name not in imaps_known ]
3484- # Remove categories with no known maps and put user at start
3485- cats_plot = {unknown : imaps_unknown , ** cats_plot }
3486- cats_plot = {cat : maps for cat , maps in cats_plot .items () if maps }
3521+ cmapdict = {}
3522+ names_all = list (map (str .lower , names ))
3523+ names_known = sum (CMAPS_TABLE .values (), [])
3524+ cmapdict [unknown ] = [name for name in names if name not in names_known ]
3525+ for cat , names in CMAPS_TABLE .items ():
3526+ cmapdict [cat ] = [name for name in names if name .lower () in names_all ]
34873527
3488- # Figure
3489- from . import subplots
3490- naxs = len (imaps_known ) + len (imaps_unknown ) + len (cats_plot )
3491- fig , axs = subplots (
3492- nrows = naxs , axwidth = length , axheight = width ,
3493- share = 0 , hspace = 0.03 ,
3494- )
3495- iax = - 1
3496- ntitles = nplots = 0 # for deciding which axes to plot in
3497- a = np .linspace (0 , 1 , 257 ).reshape (1 , - 1 )
3498- a = np .vstack ((a , a ))
3499- for cat , names in cats_plot .items ():
3500- # Space for title
3501- if not names :
3502- continue
3503- ntitles += 1
3504- for imap , name in enumerate (names ):
3505- # Draw colorbar
3506- iax += 1
3507- if imap + ntitles + nplots > naxs :
3508- break
3509- ax = axs [iax ]
3510- if imap == 0 : # allocate this axes for title
3511- iax += 1
3512- ax .set_visible (False )
3513- ax = axs [iax ]
3514- if name not in mcm .cmap_d or name .lower (
3515- ) not in imaps : # i.e. the expected builtin colormap is missing
3516- ax .set_visible (False ) # empty space
3517- continue
3518- ax .imshow (a , cmap = name , origin = 'lower' , aspect = 'auto' , levels = N )
3519- ax .format (ylabel = name ,
3520- ylabel_kw = {'rotation' : 0 , 'ha' : 'right' , 'va' : 'center' },
3521- xticks = 'none' , yticks = 'none' , # no ticks
3522- xloc = 'neither' , yloc = 'neither' , # no spines
3523- title = (cat if imap == 0 else None ))
3524- # Space for plots
3525- nplots += len (names )
3526- return fig
3528+ # Return figure of colorbars
3529+ return _draw_bars (cmapdict , ** kwargs )
35273530
35283531
3529- def show_cycles (* args , axwidth = 1.5 ):
3532+ def show_cycles (* args , ** kwargs ):
35303533 """
3531- Visualize all registered color cycles, or the list of cycle names if
3532- positional arguments are passed.
3534+ Generate a table of registered color cycles or the input color cycles.
35333535
35343536 Parameters
35353537 ----------
35363538 *args : colormap-spec, optional
3537- Positional arguments are cycle names or objects. Default is
3538- all of the registered colormaps.
3539- axwidth : str or float, optional
3540- Average width of each subplot. Units are interpreted by
3539+ Cycle names or objects.
3540+ length : float or str, optional
3541+ The length of the colorbars. Units are interpreted by
3542+ `~proplot.utils.units`.
3543+ width : float or str, optional
3544+ The width of the colorbars. Units are interpreted by
35413545 `~proplot.utils.units`.
35423546
35433547 Returns
35443548 -------
35453549 `~proplot.subplots.Figure`
3546- The figure instance .
3550+ The figure.
35473551 """
35483552 # Get the list of cycles
35493553 if args :
3550- icycles = {
3551- getattr (cycle , 'name' , '_no_name' ): Colors (cycle )
3552- for cycle in args }
3554+ names = [cmap .name for cmap in args ]
35533555 else :
3554- # use global cycles variable
3555- icycles = {key : mcm .cmap_d [key ].colors for key in cycles }
3556- nrows = len (icycles ) // 3 + len (icycles ) % 3
3556+ names = [
3557+ name for name in mcm .cmap_d .keys () if
3558+ isinstance (mcm .cmap_d [name ], ListedColormap )
3559+ ]
35573560
3558- # Create plot
3559- from . import subplots
3560- state = np .random .RandomState (51423 )
3561- fig , axs = subplots (
3562- ncols = 3 , nrows = nrows , aspect = 1 , axwidth = axwidth ,
3563- sharey = False , sharex = False , axpad = 0.05
3564- )
3565- for i , (ax , (key , cycle )) in enumerate (zip (axs , icycles .items ())):
3566- key = key .lower ()
3567- array = state .rand (20 , len (cycle )) - 0.5
3568- array = array [:, :1 ] + array .cumsum (axis = 0 ) + np .arange (0 , len (cycle ))
3569- for j , color in enumerate (cycle ):
3570- l , = ax .plot (array [:, j ], lw = 5 , ls = '-' , color = color )
3571- # make first lines have big zorder
3572- l .set_zorder (10 + len (cycle ) - j )
3573- title = f'{ key } : { len (cycle )} colors'
3574- ax .set_title (title )
3575- ax .grid (True )
3576- for axis in 'xy' :
3577- ax .tick_params (axis = axis ,
3578- which = 'both' , labelbottom = False , labelleft = False ,
3579- bottom = False , top = False , left = False , right = False )
3580- if axs [i + 1 :]:
3581- axs [i + 1 :].set_visible (False )
3582- return fig
3561+ # Return figure of colorbars
3562+ cmapdict = {'Color cycles' : names }
3563+ return _draw_bars (cmapdict , ** kwargs )
35833564
35843565
35853566def show_fonts (* args , size = 12 , text = None ):
35863567 """
3587- Visualize the available sans-serif fonts. If a glyph is unavailable,
3588- it is replaced by the "¤" dummy character.
3568+ Generate a table of fonts. If a glyph for a particular font is unavailable,
3569+ it is replaced with the "¤" dummy character.
35893570
35903571 Parameters
35913572 ----------
0 commit comments