Beispiel #1
0
def create_cmap_overview(cmaps=None,
                         *,
                         savefig=None,
                         use_types=True,
                         sort='alphabetical',
                         show_grayscale=True,
                         plot_profile=False,
                         dark_mode=False,
                         title="Colormap Overview",
                         wscale=1,
                         hscale=1):
    """
    Creates an overview plot containing all colormaps defined in the provided
    `cmaps`.

    Optional
    --------
    cmaps : list of {str; :obj:`~matplotlib.colors.Colormap` objects}, dict \
        of lists or None. Default: None
        A list of all colormaps that must be included in the overview plot.
        If dict of lists, the keys define categories for the colormaps.
        If *None*, all colormaps defined in *CMasher* are used instead.
    savefig : str or None. Default: None
        If not *None*, the path where the overview plot must be saved to.
        Else, the plot will simply be shown.
    use_types : bool. Default: True
        Whether all colormaps in `cmaps` should be categorized into their
        colormap types (sequential; diverging; cyclic; qualitative; misc).
        If `cmaps` is a dict, this value is ignored.
    sort : {'alphabetical'/'name'; 'lightness'}, function or None. Default: \
        'alphabetical'
        String or function indicating how the colormaps should be sorted in the
        overview.
        If 'alphabetical', the colormaps are sorted alphabetically on their
        name.
        If 'lightness', the colormaps are sorted based on their lightness
        profile.
        If function, a function definition that takes a
        :obj:`~matplotlib.colors.Colormap` object and returns the sorted
        position of that colormap.
        If *None*, the colormaps retain the order they were given in.
    show_grayscale : bool. Default: True
        Whether to show the grayscale versions of the given `cmaps` in the
        overview.
    plot_profile : bool or float. Default: False
        Whether the lightness profiles of all colormaps should be plotted. If
        not *False*, the lightness profile of a colormap is plotted on top of
        its gray-scale version and `plot_profile` is used for setting the alpha
        (opacity) value.
        If `plot_profile` is *True*, it will be set to `0.25`.
        If `show_grayscale` is *False*, this value is ignored.
    dark_mode : bool. Default: False
        Whether the colormap overview should be created using mostly dark
        colors.
    title : str or None. Default: "Colormap Overview"
        String to be used as the title of the colormap overview.
        If empty or *None*, no title will be used.
    wscale, hscale : float. Default: (1, 1)
        Floats that determine with what factor the colormap subplot dimensions
        in the overview should be scaled with.
        The default values uses the default dimensions for the subplots (which
        are determined by other input arguments).

    Notes
    -----
    The colormaps in `cmaps` can either be provided as their registered name in
    :mod:`matplotlib.cm`, or their corresponding
    :obj:`~matplotlib.colors.Colormap` object.
    Any provided reversed colormaps (colormaps that end their name with '_r')
    are ignored if their normal versions were provided as well.

    If `plot_profile` is not set to *False*, the lightness profiles are plotted
    on top of the gray-scale colormap versions, where the y-axis ranges from 0%
    lightness to 100% lightness.
    The lightness profile transitions between black and white at 50% lightness.

    """

    # Check value of show_grayscale
    if show_grayscale:
        # If True, the overview will have two columns
        ncols = 2
    else:
        # If False, the overview will have one column and no profile plotted
        ncols = 1
        wscale *= 0.5
        plot_profile = False

    # Determine positions
    wscale = 0.2 + 0.8 * wscale
    left_pos = 0.2 / wscale
    spacing = 0.01 / wscale

    # If plot_profile is True, set it to its default value
    if plot_profile is True:
        plot_profile = 0.25

    # Check if dark mode is requested
    if dark_mode:
        # If so, use dark grey for the background and light grey for the text
        edge_color = '#24292E'
        face_color = '#24292E'
        text_color = '#9DA5B4'
    else:
        # If not, use white for the background and black for the text
        edge_color = '#FFFFFF'
        face_color = '#FFFFFF'
        text_color = '#000000'

    # If cmaps is None, use cmap_d.values
    if cmaps is None:
        cmaps = cmrcm.cmap_d.values()

    # If sort is a string, obtain proper function
    if isinstance(sort, str):
        # Convert sort to lowercase
        sort = sort.lower()

        # Check what string was provided and obtain sorting function
        if sort in ('alphabetical', 'name'):

            def sort(x):
                return (x.name)
        elif (sort == 'lightness'):
            sort = _get_cmap_lightness_rank

    # Create empty list of cmaps
    cmaps_list = []

    # If cmaps is a dict, it has cm_types defined
    if isinstance(cmaps, dict):
        # Set use_types to True
        use_types = True

        # Define empty dict of colormaps
        cmaps_dict = odict()

        # Save provided cmaps as something else
        input_cmaps = cmaps

        # Loop over all cm_types
        for cm_type, cmaps in input_cmaps.items():
            # Add empty list of colormaps to cmaps_dict with this cm_type
            cmaps_dict[cm_type] = []

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, str):
                    cmaps_dict[cm_type].append(mplcm.get_cmap(cmap))
                else:
                    cmaps_dict[cm_type].append(cmap)

    # Else, it is a list with no cm_types
    else:
        # If cm_types are requested
        if use_types:
            # Define empty dict with the base cm_types
            cm_types = [
                'sequential', 'diverging', 'cyclic', 'qualitative', 'misc'
            ]
            cmaps_dict = odict([[cm_type, []] for cm_type in cm_types])

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                cm_type = get_cmap_type(cmap)
                if isinstance(cmap, str):
                    cmaps_dict[cm_type].append(mplcm.get_cmap(cmap))
                else:
                    cmaps_dict[cm_type].append(cmap)
        else:
            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, str):
                    cmaps_list.append(mplcm.get_cmap(cmap))
                else:
                    cmaps_list.append(cmap)

    # If use_types is True, a dict is currently used
    if use_types:
        # Convert entire cmaps_dict into a list again
        for key, value in cmaps_dict.items():
            # If this cm_type has at least 1 colormap, sort and add them
            if value:
                # Obtain the names of all colormaps
                names = [x.name for x in value]

                # Remove all reversed colormaps that also have their original
                off_dex = len(names) - 1
                for i, name in enumerate(reversed(names)):
                    if name.endswith('_r') and name[:-2] in names:
                        value.pop(off_dex - i)

                # Sort the colormaps if requested
                if sort is not None:
                    value.sort(key=sort)

                # Add to list
                cmaps_list.append((key, False))
                cmaps_list.extend(value)

    # Else, a list is used
    else:
        # Obtain the names of all colormaps
        names = [x.name for x in cmaps_list]

        # Remove all reversed colormaps that also have their original
        off_dex = len(names) - 1
        for i, name in enumerate(reversed(names)):
            if name.endswith('_r') and name[:-2] in names:
                cmaps_list.pop(off_dex - i)

        # Sort the colormaps if requested
        if sort is not None:
            cmaps_list.sort(key=sort)

    # Add title to cmaps_list if requested
    if title:
        cmaps_list.insert(0, (title, True))

    # Obtain the colorspace converter for showing cmaps in grey-scale
    cspace_convert = cspace_converter("sRGB1", "CAM02-UCS")

    # Create figure instance
    height = (0.4 * len(cmaps_list) + 0.1) * hscale
    fig, axs = plt.subplots(figsize=(6.4 * wscale, height),
                            nrows=len(cmaps_list),
                            ncols=ncols,
                            edgecolor=edge_color,
                            facecolor=face_color)

    # Adjust subplot positioning
    fig.subplots_adjust(top=(1 - 0.05 / height),
                        bottom=0.05 / height,
                        left=left_pos,
                        right=1.0 - spacing,
                        wspace=0.05)

    # If cmaps_list only has a single element, make sure axs is a list
    if (len(cmaps_list) == 1):
        axs = [axs]

    # Loop over all cmaps defined in cmaps list
    for ax, cmap in zip(axs, cmaps_list):
        # Obtain axes objects and turn them off
        if show_grayscale:
            # Obtain Axes objects
            ax0, ax1 = ax

            # Turn axes off
            ax0.set_axis_off()
            ax1.set_axis_off()
        else:
            # Obtain Axes object
            ax0 = ax

            # Turn axis off
            ax0.set_axis_off()

        # Obtain position bbox of ax0
        pos0 = ax0.get_position()

        # If cmap is a tuple, it defines a title or cm_type
        if isinstance(cmap, tuple):
            # Calculate title_pos
            title_pos = left_pos + (1 - spacing - left_pos) / 2

            # If it is a title
            if cmap[1]:
                # Write the title as text in the correct position
                fig.text(title_pos,
                         pos0.y0 + pos0.height / 2,
                         cmap[0],
                         va='center',
                         ha='center',
                         fontsize=18,
                         c=text_color)

            # If it is a cm_type
            else:
                # Write the cm_type as text in the correct position
                fig.text(title_pos,
                         pos0.y0,
                         cmap[0],
                         va='bottom',
                         ha='center',
                         fontsize=14,
                         c=text_color)

        # Else, this is a colormap
        else:
            # Obtain the colormap type
            cm_type = get_cmap_type(cmap)

            # Get array of all values for which a colormap value is requested
            x = np.arange(cmap.N)

            # Get RGB values for colormap
            rgb = cmap(x)[:, :3]

            # Get lightness values of colormap
            lab = cspace_convert(rgb)
            L = lab[:, 0]

            # Normalize lightness values
            L /= 99.99871678

            # Get corresponding RGB values for lightness values using neutral
            rgb_L = cmrcm.neutral(L)[:, :3]

            # Add colormap subplot
            ax0.imshow(rgb[np.newaxis, ...], aspect='auto')

            # Check if the lightness profile was requested
            if plot_profile and (cm_type != 'qualitative'):
                # Determine the points that need to be plotted
                plot_L = -(L - 0.5)
                points = np.stack([x, plot_L], axis=1)

                # Determine the colors that each point must have
                # Use black for L >= 0.5 and white for L <= 0.5.
                colors = np.zeros_like(plot_L, dtype=int)
                colors[plot_L >= 0] = 1

                # Split points up into segments with the same color
                s_idx = np.nonzero(np.diff(colors))[0] + 1
                segments = np.split(points, s_idx)

                # Loop over all pairs of adjacent segments
                for i, (seg1,
                        seg2) in enumerate(zip(segments[:-1], segments[1:])):
                    # Determine the point in the center of these segments
                    central_point = (seg1[-1] + seg2[0]) / 2

                    # Add this point to the ends of these segments
                    # This ensures that the color changes in between segments
                    segments[i] = np.concatenate(
                        [segments[i], [central_point]], axis=0)
                    segments[i + 1] = np.concatenate(
                        [[central_point], segments[i + 1]], axis=0)

                # Create an MPL LineCollection object with these segments
                lc = LineCollection(segments,
                                    cmap=cmrcm.neutral,
                                    alpha=plot_profile)
                lc.set_linewidth(1)

                # Determine the colors of each segment
                s_colors = [colors[0]]
                s_colors.extend(colors[s_idx])
                s_colors = np.array(s_colors)

                # Set the values of the line-collection to be these colors
                lc.set_array(s_colors)

                # Add line-collection to this subplot
                ax1.add_collection(lc)

            # Add gray-scale colormap subplot if requested
            if show_grayscale:
                ax1.imshow(rgb_L[np.newaxis, ...], aspect='auto')

            # Plot the name of the colormap as text
            x_text = pos0.x0 - spacing
            y_text = pos0.y0 + pos0.height / 2
            fig.text(x_text,
                     y_text,
                     cmap.name,
                     va='center',
                     ha='right',
                     fontsize=10,
                     c=text_color)

    # If savefig is not None, save the figure
    if savefig is not None:
        dpi = 100 if (path.splitext(savefig)[1] == '.svg') else 250
        plt.savefig(savefig,
                    dpi=dpi,
                    facecolor=face_color,
                    edgecolor=edge_color)
        plt.close(fig)

    # Else, simply show it
    else:
        plt.show()
Beispiel #2
0
def create_cmap_overview(cmaps=None, savefig=None, use_types=True):
    """
    Creates an overview plot containing all colormaps defined in the provided
    `cmaps`.

    Optional
    --------
    cmaps : list of {str; :obj:`~matplotlib.colors.Colormap` objects}, dict \
        of lists or None. Default: None
        A list of all colormaps that must be included in the overview plot.
        If dict of lists, the keys define categories for the colormaps.
        If *None*, all colormaps defined in *CMasher* are used instead.
    savefig : str or None. Default: None
        If not *None*, the path where the overview plot must be saved to.
        Else, the plot will simply be shown.
    use_types : bool. Default: True
        Whether all colormaps in `cmaps` should be categorized into their
        colormap types (sequential; diverging; cyclic; qualitative; misc).
        If `cmaps` is a dict, this value is ignored.

    Note
    ----
    The colormaps in `cmaps` can either be provided as their registered name in
    *MPL*, or their corresponding :obj:`~matplotlib.colors.Colormap` object.
    Any provided reversed colormaps (colormaps that end their name with '_r')
    are ignored.

    """

    # If cmaps is None, use cmap_d.values
    if cmaps is None:
        cmaps = cmrcm.cmap_d.values()

    # Create empty list of cmaps
    cmaps_list = []

    # If cmaps is a dict, it has cm_types defined
    if isinstance(cmaps, dict):
        # Define empty dict of colormaps
        cmaps_dict = odict()

        # Save provided cmaps as something else
        input_cmaps = cmaps

        # Loop over all cm_types
        for cm_type, cmaps in input_cmaps.items():
            # Add empty list of colormaps to cmaps_dict with this cm_type
            cmaps_dict[cm_type] = []
            type_lst = cmaps_dict[cm_type]

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, string_types) and not cmap.endswith('_r'):
                    type_lst.append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    type_lst.append(cmap)

            # Sort the colormaps in this cm_type
            type_lst.sort(key=lambda x: x.name)

        # Convert entire cmaps_dict into a list again
        for key, value in cmaps_dict.items():
            # If this cm_type has at least 1 colormap, add them
            if value:
                cmaps_list.append(key)
                cmaps_list.extend(value)

    # Else, it is a list with no cm_types
    else:
        # If cm_types are requested
        if use_types:
            # Define empty dict with the base cm_types
            cm_types = [
                'sequential', 'diverging', 'cyclic', 'qualitative', 'misc'
            ]
            cmaps_dict = odict([[cm_type, []] for cm_type in cm_types])

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                cm_type = _get_cm_type(cmap)
                if isinstance(cmap, string_types) and not cmap.endswith('_r'):
                    cmaps_dict[cm_type].append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    cmaps_dict[cm_type].append(cmap)

            # Loop over all cm_types and sort their colormaps
            for cm_type in cm_types:
                cmaps_dict[cm_type].sort(key=lambda x: x.name)

            # Convert entire cmaps_dict into a list again
            for key, value in cmaps_dict.items():
                # If this cm_type has at least 1 colormap, add them
                if value:
                    cmaps_list.append(key)
                    cmaps_list.extend(value)
        else:
            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, string_types) and not cmap.endswith('_r'):
                    cmaps_list.append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    cmaps_list.append(cmap)
            cmaps_list.sort(key=lambda x: x.name)

    # Obtain the colorspace converter for showing cmaps in grey-scale
    cspace_convert = cspace_converter("sRGB1", "CAM02-UCS")

    # Create figure instance
    height = 0.4 * (len(cmaps_list) + 1)
    fig, axes = plt.subplots(figsize=(6.4, height),
                             nrows=len(cmaps_list),
                             ncols=2)
    w_pad, h_pad, wspace, hspace = fig.get_constrained_layout_pads()
    fig.subplots_adjust(top=(1 - 0.24 / height),
                        bottom=0.01,
                        left=0.2,
                        right=0.99,
                        wspace=0.05)
    fig.suptitle("Colormap Overview", fontsize=16, y=1.0, x=0.595)

    # If cmaps_list only has a single element, make sure axes is a list
    if (len(cmaps_list) == 1):
        axes = [axes]

    # Loop over all cmaps defined in cmaps list
    for ax, cmap in zip(axes, cmaps_list):
        # Turn axes off
        ax[0].set_axis_off()
        ax[1].set_axis_off()

        # If cmap is a string, it defines a cm_type
        if isinstance(cmap, string_types):
            # Write the cm_type as text in the correct position
            fig.text(0.595,
                     ax[0].get_position().bounds[1],
                     cmap,
                     va='bottom',
                     ha='center',
                     fontsize=14)

        # Else, this is a colormap
        else:
            # Get array of all values for which a colormap value is requested
            x = np.linspace(0, 1, cmap.N)

            # Get RGB values for colormap
            rgb = cmap(x)[:, :3]

            # Get lightness values of colormap
            lab = cspace_convert(rgb)
            L = lab[:, 0]

            # Get corresponding RGB values for lightness values using neutral
            rgb_L = cmrcm.neutral(L / 99.99871678)[:, :3]

            # Add subplots
            ax[0].imshow(rgb[np.newaxis, ...], aspect='auto')
            ax[1].imshow(rgb_L[np.newaxis, ...], aspect='auto')
            pos = list(ax[0].get_position().bounds)
            x_text = pos[0] - 0.01
            y_text = pos[1] + pos[3] / 2
            fig.text(x_text,
                     y_text,
                     cmap.name,
                     va='center',
                     ha='right',
                     fontsize=10)

    # If savefig is not None, save the figure
    if savefig is not None:
        plt.savefig(savefig, dpi=250)
        plt.close(fig)

    # Else, simply show it
    else:
        plt.show()
Beispiel #3
0
def create_cmap_overview(cmaps=None,
                         savefig=None,
                         use_types=True,
                         sort='alphabetical',
                         plot_profile=False):
    """
    Creates an overview plot containing all colormaps defined in the provided
    `cmaps`.

    Optional
    --------
    cmaps : list of {str; :obj:`~matplotlib.colors.Colormap` objects}, dict \
        of lists or None. Default: None
        A list of all colormaps that must be included in the overview plot.
        If dict of lists, the keys define categories for the colormaps.
        If *None*, all colormaps defined in *CMasher* are used instead.
    savefig : str or None. Default: None
        If not *None*, the path where the overview plot must be saved to.
        Else, the plot will simply be shown.
    use_types : bool. Default: True
        Whether all colormaps in `cmaps` should be categorized into their
        colormap types (sequential; diverging; cyclic; qualitative; misc).
        If `cmaps` is a dict, this value is ignored.
    sort : {'alphabetical'/'name'; 'lightness'} or None. Default: \
        'alphabetical'
        String indicating how the colormaps should be sorted in the overview.
        If 'alphabetical', the colormaps are sorted alphabetically on their
        name.
        If 'lightness', the colormaps are sorted on their starting lightness
        and their lightness range.
        If *None*, the colormaps retain the order they were given in.
    plot_profile : bool or float. Default: False
        Whether the lightness profiles of all colormaps should be plotted. If
        not *False*, the lightness profile of a colormap is plotted on top of
        its gray-scale version and `plot_profile` is used for setting the alpha
        (opacity) value.
        If `plot_profile` is *True*, it will be set to `0.25`.

    Notes
    -----
    The colormaps in `cmaps` can either be provided as their registered name in
    :mod:`matplotlib.cm`, or their corresponding
    :obj:`~matplotlib.colors.Colormap` object.
    Any provided reversed colormaps (colormaps that end their name with '_r')
    are ignored.

    If `plot_profile` is not set to *False*, the lightness profiles are plotted
    on top of the gray-scale colormap versions, where the y-axis ranges from 0%
    lightness to 100% lightness.
    The lightness profile transitions between black and white at 50% lightness.

    """

    # If plot_profile is True, set it to its default value
    if plot_profile is True:
        plot_profile = 0.25

    # If cmaps is None, use cmap_d.values
    if cmaps is None:
        cmaps = cmrcm.cmap_d.values()

    # If sort is a string, convert to lowercase
    if isinstance(sort, string_types):
        sort = sort.lower()

    # Create empty list of cmaps
    cmaps_list = []

    # If cmaps is a dict, it has cm_types defined
    if isinstance(cmaps, dict):
        # Set use_types to True
        use_types = True

        # Define empty dict of colormaps
        cmaps_dict = odict()

        # Save provided cmaps as something else
        input_cmaps = cmaps

        # Loop over all cm_types
        for cm_type, cmaps in input_cmaps.items():
            # Add empty list of colormaps to cmaps_dict with this cm_type
            cmaps_dict[cm_type] = []

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, string_types):
                    if not cmap.endswith('_r'):
                        cmaps_dict[cm_type].append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    cmaps_dict[cm_type].append(cmap)

    # Else, it is a list with no cm_types
    else:
        # If cm_types are requested
        if use_types:
            # Define empty dict with the base cm_types
            cm_types = [
                'sequential', 'diverging', 'cyclic', 'qualitative', 'misc'
            ]
            cmaps_dict = odict([[cm_type, []] for cm_type in cm_types])

            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                cm_type = get_cmap_type(cmap)
                if isinstance(cmap, string_types):
                    if not cmap.endswith('_r'):
                        cmaps_dict[cm_type].append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    cmaps_dict[cm_type].append(cmap)
        else:
            # Loop over all cmaps and remove reversed versions
            for cmap in cmaps:
                if isinstance(cmap, string_types):
                    if not cmap.endswith('_r'):
                        cmaps_list.append(mplcm.get_cmap(cmap))
                elif not cmap.name.endswith('_r'):
                    cmaps_list.append(cmap)

    # If use_types is True, a dict is currently used
    if use_types:
        # Convert entire cmaps_dict into a list again
        for key, value in cmaps_dict.items():
            # If this cm_type has at least 1 colormap, sort and add them
            if value:
                # Sort on lightness if requested and this cm_type is compatible
                if ((sort == 'lightness')
                        and (key not in ('qualitative', 'misc'))):
                    value.sort(key=_get_cmap_lightness_rank)
                # Else, sort on name
                elif sort in ('alphabetical', 'name'):
                    value.sort(key=lambda x: x.name)

                # Add to list
                cmaps_list.append(key)
                cmaps_list.extend(value)

    # Else, a list is used
    else:
        # Sort the colormaps
        if (sort == 'lightness'):
            cmaps_list.sort(key=_get_cmap_lightness_rank)
        elif sort in ('alphabetical', 'name'):
            cmaps_list.sort(key=lambda x: x.name)

    # Obtain the colorspace converter for showing cmaps in grey-scale
    cspace_convert = cspace_converter("sRGB1", "CAM02-UCS")

    # Create figure instance
    height = 0.4 * (len(cmaps_list) + 1)
    fig, axes = plt.subplots(figsize=(6.4, height),
                             nrows=len(cmaps_list),
                             ncols=2)
    fig.subplots_adjust(top=(1 - 0.24 / height),
                        bottom=0.048 / height,
                        left=0.2,
                        right=0.99,
                        wspace=0.05)
    fig.suptitle("Colormap Overview", fontsize=16, y=1.0, x=0.595)

    # If cmaps_list only has a single element, make sure axes is a list
    if (len(cmaps_list) == 1):
        axes = [axes]

    # Set the current cm_type to None
    cm_type = None

    # Loop over all cmaps defined in cmaps list
    for ax, cmap in zip(axes, cmaps_list):
        # Turn axes off
        ax[0].set_axis_off()
        ax[1].set_axis_off()

        # If cmap is a string, it defines a cm_type
        if isinstance(cmap, string_types):
            # Write the cm_type as text in the correct position
            fig.text(0.595,
                     ax[0].get_position().bounds[1],
                     cmap,
                     va='bottom',
                     ha='center',
                     fontsize=14)

            # Save what the current cm_type is
            cm_type = cmap

        # Else, this is a colormap
        else:
            # Get array of all values for which a colormap value is requested
            x = np.arange(cmap.N)

            # Get RGB values for colormap
            rgb = cmap(x)[:, :3]

            # Get lightness values of colormap
            lab = cspace_convert(rgb)
            L = lab[:, 0]

            # Normalize lightness values
            L /= 99.99871678

            # Get corresponding RGB values for lightness values using neutral
            rgb_L = cmrcm.neutral(L)[:, :3]

            # Add colormap subplot
            ax[0].imshow(rgb[np.newaxis, ...], aspect='auto')

            # Check if the lightness profile was requested
            if plot_profile and (cm_type != 'qualitative'):
                # Determine the points that need to be plotted
                plot_L = -(L - 0.5)
                points = np.stack([x, plot_L], axis=1)

                # Determine the colors that each point must have
                # Use black for L >= 0.5 and white for L <= 0.5.
                colors = np.zeros_like(plot_L, dtype=int)
                colors[plot_L >= 0] = 1

                # Split points up into segments with the same color
                s_idx = np.nonzero(np.diff(colors))[0] + 1
                segments = np.split(points, s_idx)

                # Loop over all pairs of adjacent segments
                for i, (seg1,
                        seg2) in enumerate(zip(segments[:-1], segments[1:])):
                    # Determine the point in the center of these segments
                    central_point = (seg1[-1] + seg2[0]) / 2

                    # Add this point to the ends of these segments
                    # This ensures that the color changes in between segments
                    segments[i] = np.concatenate(
                        [segments[i], [central_point]], axis=0)
                    segments[i + 1] = np.concatenate(
                        [[central_point], segments[i + 1]], axis=0)

                # Create an MPL LineCollection object with these segments
                lc = LineCollection(segments,
                                    cmap=cmrcm.neutral,
                                    alpha=plot_profile)
                lc.set_linewidth(1)

                # Determine the colors of each segment
                s_colors = [colors[0]]
                s_colors.extend(colors[s_idx])
                s_colors = np.array(s_colors)

                # Set the values of the line-collection to be these colors
                lc.set_array(s_colors)

                # Add line-collection to this subplot
                ax[1].add_collection(lc)

            # Add gray-scale colormap subplot
            ax[1].imshow(rgb_L[np.newaxis, ...], aspect='auto')

            # Plot the name of the colormap as text
            pos = list(ax[0].get_position().bounds)
            x_text = pos[0] - 0.01
            y_text = pos[1] + pos[3] / 2
            fig.text(x_text,
                     y_text,
                     cmap.name,
                     va='center',
                     ha='right',
                     fontsize=10)

    # If savefig is not None, save the figure
    if savefig is not None:
        dpi = 100 if (path.splitext(savefig)[1] == '.svg') else 250
        plt.savefig(savefig, dpi=dpi)
        plt.close(fig)

    # Else, simply show it
    else:
        plt.show()