Example #1
0
def CIE_1931_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer',
        show_diagram_colours=True,
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    show_diagram_colours : bool, optional
        Display the chromaticity diagram background colours.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    if show_diagram_colours:
        image = matplotlib.image.imread(
            os.path.join(PLOTTING_RESOURCES_DIRECTORY,
                         'CIE_1931_Chromaticity_Diagram_{0}.png'.format(
                             cmfs.name.replace(' ', '_'))))
        pylab.imshow(image, interpolation=None, extent=(0, 1, 0, 1))

    labels = (
        390, 460, 470, 480, 490, 500, 510, 520, 540, 560, 580, 600, 620, 700)

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    xy = XYZ_to_xy(cmfs.values, illuminant)

    wavelengths_chromaticity_coordinates = dict(tuple(zip(wavelengths, xy)))

    pylab.plot(xy[..., 0], xy[..., 1], color='black', linewidth=2)
    pylab.plot((xy[-1][0], xy[0][0]),
               (xy[-1][1], xy[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        x, y = wavelengths_chromaticity_coordinates.get(label)
        pylab.plot(x, y, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else
                 wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates.get(right)[0] -
              wavelengths_chromaticity_coordinates.get(left)[0])
        dy = (wavelengths_chromaticity_coordinates.get(right)[1] -
              wavelengths_chromaticity_coordinates.get(left)[1])

        xy = np.array([x, y])
        direction = np.array([-dy, dx])

        normal = (np.array([-dy, dx])
                  if np.dot(normalise_vector(xy - equal_energy),
                            normalise_vector(direction)) > 0 else
                  np.array([dy, -dx]))
        normal = normalise_vector(normal)
        normal /= 25

        pylab.plot((x, x + normal[0] * 0.75),
                   (y, y + normal[1] * 0.75),
                   color='black',
                   linewidth=1.5)
        pylab.text(x + normal[0],
                   y + normal[1],
                   label,
                   color='black',
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    ticks = np.arange(-10, 10, 0.1)

    pylab.xticks(ticks)
    pylab.yticks(ticks)

    settings.update({
        'title': 'CIE 1931 Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label': 'CIE x',
        'y_label': 'CIE y',
        'grid': True,
        'bounding_box': (0, 1, 0, 1)})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
def plot_grid(filename, data_points, grid, bbox_xystar, xystar=True):
    if not have_matplotlib or not have_colour_package:
        return

    print("Plotting the grid ...")

    plt.figure()
    # Draw a nice chromaticity diagram.
    clr.CIE_1931_chromaticity_diagram_plot(standalone=False)
    clr.canvas(figure_size=(7,7))

    # Show the sRGB gamut.
    color_space = clr.get_RGB_colourspace('sRGB')
    x = color_space.primaries[:,0].tolist()
    y = color_space.primaries[:,1].tolist()
    plt.fill(x, y, color='black', label='sRGB', fill=False)

    # Draw crosses into all internal grid cells.
    # for gridcell in grid:
    #     if len(gridcell.indices) > 0 and gridcell.inside:
    #         if xystar:
    #             pointx = sum([data_points[i].xystar[0] for i in gridcell.indices])
    #             pointy = sum([data_points[i].xystar[1] for i in gridcell.indices])
    #             pointx /= len(gridcell.indices)
    #             pointy /= len(gridcell.indices)
    #             (pointx, pointy) = Transform.xy_from_xystar((pointx, pointy))
    #             plt.plot(pointx, pointy, "x", color="black")
    #         else:
    #             pointx = sum([data_points[i].uv[0] for i in gridcell.indices])
    #             pointy = sum([data_points[i].uv[1] for i in gridcell.indices])
    #             pointx /= len(gridcell.indices)
    #             pointy /= len(gridcell.indices)
    #             (pointx, pointy) = Transform.xy_from_uv((pointx, pointy))
    #             plt.plot(pointx, pointy, "x", color="black")
 
    # Draw data points.
    for i, data_point in enumerate(data_points):
        if xystar:
            p = Transform.xy_from_xystar(data_point.xystar)
        else:
            p = Transform.xy_from_uv(data_point.uv)

        if data_point.equal_energy_white:
            plt.plot(p[0], p[1], "o", color="white", ms=4)
        elif data_point.broken:
            plt.plot(p[0], p[1], "o", color="red", ms=4)
        else:
            plt.plot(p[0], p[1], "o", color="green", ms=4)

        # Show grid point indices, for debugging.
        # plt.text(p[0]+0.01, p[1]-0.01, '{}'.format(i))

    bp0 = Transform.xy_from_xystar([bbox_xystar[0][0], bbox_xystar[0][1]])
    bp1 = Transform.xy_from_xystar([bbox_xystar[0][0], bbox_xystar[1][1]])
    bp2 = Transform.xy_from_xystar([bbox_xystar[1][0], bbox_xystar[1][1]])
    bp3 = Transform.xy_from_xystar([bbox_xystar[1][0], bbox_xystar[0][1]])
    plt.plot([bp0[0], bp1[0], bp2[0], bp3[0], bp0[0]],
             [bp0[1], bp1[1], bp2[1], bp3[1], bp0[1]],
             label="Grid Bounding Box")

    plt.xlabel('$x$')
    plt.ylabel('$y$')

    plt.legend()
    plt.savefig(filename)
Example #3
0
def RGB_colourspaces_CIE_1931_chromaticity_diagram_plot(
        colourspaces=None,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots given *RGB* colourspaces in *CIE 1931 Chromaticity Diagram*.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.
    show_diagram_colours : bool, optional
        {:func:`CIE_1931_chromaticity_diagram_plot`},
        Whether to display the chromaticity diagram background colours.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_CIE_1931_chromaticity_diagram_plot(
    ...     c)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut')

    cmfs, name = get_cmfs(cmfs), cmfs

    settings = {
        'title':
        '{0} - {1} - CIE 1931 Chromaticity Diagram'.format(
            ', '.join(colourspaces), name),
        'standalone':
        False
    }
    settings.update(kwargs)

    CIE_1931_chromaticity_diagram_plot(**settings)

    x_limit_min, x_limit_max = [-0.1], [0.9]
    y_limit_min, y_limit_max = [-0.1], [0.9]

    settings = {
        'colour_cycle_map': 'rainbow',
        'colour_cycle_count': len(colourspaces)
    }
    settings.update(kwargs)

    cycle = colour_cycle(**settings)

    for colourspace in colourspaces:
        if colourspace == 'Pointer Gamut':
            xy = np.asarray(POINTER_GAMUT_BOUNDARIES)
            alpha_p, colour_p = 0.85, '0.95'
            pylab.plot(xy[..., 0],
                       xy[..., 1],
                       label='Pointer\'s Gamut',
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)
            pylab.plot((xy[-1][0], xy[0][0]), (xy[-1][1], xy[0][1]),
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)

            XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                             POINTER_GAMUT_ILLUMINANT)
            xy = XYZ_to_xy(XYZ, POINTER_GAMUT_ILLUMINANT)
            pylab.scatter(xy[..., 0],
                          xy[..., 1],
                          alpha=alpha_p / 2,
                          color=colour_p,
                          marker='+')

        else:
            colourspace, name = get_RGB_colourspace(colourspace), colourspace

            r, g, b, _a = next(cycle)

            primaries = colourspace.primaries
            whitepoint = colourspace.whitepoint

            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       color=(r, g, b),
                       label=colourspace.name,
                       linewidth=2)
            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       'o',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[0, 0], primaries[1, 0]),
                       (primaries[0, 1], primaries[1, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[1, 0], primaries[2, 0]),
                       (primaries[1, 1], primaries[2, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[2, 0], primaries[0, 0]),
                       (primaries[2, 1], primaries[0, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)

            x_limit_min.append(np.amin(primaries[..., 0]) - 0.1)
            y_limit_min.append(np.amin(primaries[..., 1]) - 0.1)
            x_limit_max.append(np.amax(primaries[..., 0]) + 0.1)
            y_limit_max.append(np.amax(primaries[..., 1]) + 0.1)

    settings.update({
        'legend':
        True,
        'legend_location':
        'upper right',
        'x_tighten':
        True,
        'y_tighten':
        True,
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max)),
        'standalone':
        True
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #4
0
def corresponding_chromaticities_prediction_plot(experiment=1,
                                                 model='Von Kries',
                                                 transform='CAT02',
                                                 **kwargs):
    """
    Plots given chromatic adaptation model corresponding chromaticities
    prediction.

    Parameters
    ----------
    experiment : int, optional
        Corresponding chromaticities prediction experiment number.
    model : unicode, optional
        Corresponding chromaticities prediction model name.
    transform : unicode, optional
        Transformation to use with Von Kries chromatic adaptation model.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> corresponding_chromaticities_prediction_plot()  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    model, name = (get_corresponding_chromaticities_prediction_model(model),
                   model)

    settings.update({
        'title':
        (('Corresponding Chromaticities Prediction\n{0} ({1}) - '
          'Experiment {2}\nCIE 1976 UCS Chromaticity Diagram').format(
              name, transform, experiment) if name.lower() in ('von kries',
                                                               'vonkries') else
         ('Corresponding Chromaticities Prediction\n{0} - '
          'Experiment {1}\nCIE 1976 UCS Chromaticity Diagram').format(
              name, experiment)),
        'standalone':
        False
    })
    settings.update(kwargs)

    CIE_1976_UCS_chromaticity_diagram_plot(**settings)

    results = model(experiment, transform=transform)

    for result in results:
        name, uvp_t, uvp_m, uvp_p = result
        pylab.arrow(uvp_t[0],
                    uvp_t[1],
                    uvp_p[0] - uvp_t[0] - 0.1 * (uvp_p[0] - uvp_t[0]),
                    uvp_p[1] - uvp_t[1] - 0.1 * (uvp_p[1] - uvp_t[1]),
                    head_width=0.005,
                    head_length=0.005,
                    linewidth=0.5,
                    color='black')
        pylab.plot(uvp_t[0], uvp_t[1], 'o', color='white')
        pylab.plot(uvp_m[0], uvp_m[1], '^', color='white')
        pylab.plot(uvp_p[0], uvp_p[1], '^', color='black')
    settings.update({
        'x_tighten': True,
        'y_tighten': True,
        'limits': (-0.1, 0.7, -0.1, 0.7),
        'standalone': True
    })

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #5
0
def CIE_1976_UCS_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer',
        show_diagram_colours=True,
        **kwargs):
    """
    Plots the *CIE 1976 UCS Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    show_diagram_colours : bool, optional
        Whether to display the chromaticity diagram background colours.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> CIE_1976_UCS_chromaticity_diagram_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    if show_diagram_colours:
        image = matplotlib.image.imread(
            os.path.join(
                PLOTTING_RESOURCES_DIRECTORY,
                'CIE_1976_UCS_Chromaticity_Diagram_{0}.png'.format(
                    cmfs.name.replace(' ', '_'))))
        pylab.imshow(image, interpolation=None, extent=(0, 1, 0, 1))

    labels = (420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540,
              550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 680)

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    uv = Luv_to_uv(XYZ_to_Luv(cmfs.values, illuminant), illuminant)

    wavelengths_chromaticity_coordinates = dict(zip(wavelengths, uv))

    pylab.plot(uv[..., 0], uv[..., 1], color='black', linewidth=2)
    pylab.plot((uv[-1][0], uv[0][0]), (uv[-1][1], uv[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        u, v = wavelengths_chromaticity_coordinates[label]
        pylab.plot(u, v, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates[right][0] -
              wavelengths_chromaticity_coordinates[left][0])
        dy = (wavelengths_chromaticity_coordinates[right][1] -
              wavelengths_chromaticity_coordinates[left][1])

        uv = np.array([u, v])
        direction = np.array([-dy, dx])

        normal = (np.array([
            -dy, dx
        ]) if np.dot(normalise_vector(uv - equal_energy),
                     normalise_vector(direction)) > 0 else np.array([dy, -dx]))
        normal = normalise_vector(normal)
        normal /= 25

        pylab.plot((u, u + normal[0] * 0.75), (v, v + normal[1] * 0.75),
                   color='black',
                   linewidth=1.5)
        pylab.text(u + normal[0],
                   v + normal[1],
                   label,
                   color='black',
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    ticks = np.arange(-10, 10, 0.1)

    pylab.xticks(ticks)
    pylab.yticks(ticks)

    settings.update({
        'title':
        'CIE 1976 UCS Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label':
        'CIE u\'',
        'y_label':
        'CIE v\'',
        'grid':
        True,
        'bounding_box': (0, 1, 0, 1)
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #6
0
def blackbody_spectral_radiance_plot(
        temperature=3500,
        cmfs='CIE 1931 2 Degree Standard Observer',
        blackbody='VY Canis Major',
        **kwargs):
    """
    Plots given blackbody spectral radiance.

    Parameters
    ----------
    temperature : numeric, optional
        Blackbody temperature.
    cmfs : unicode, optional
        Standard observer colour matching functions.
    blackbody : unicode, optional
        Blackbody name.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> blackbody_spectral_radiance_plot()  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    cmfs = get_cmfs(cmfs)

    matplotlib.pyplot.subplots_adjust(hspace=0.4)

    spd = blackbody_spd(temperature, cmfs.shape)

    matplotlib.pyplot.figure(1)
    matplotlib.pyplot.subplot(211)

    settings = {
        'title': '{0} - Spectral Radiance'.format(blackbody),
        'y_label': 'W / (sr m$^2$) / m',
        'standalone': False}
    settings.update(kwargs)

    single_spd_plot(spd, cmfs.name, **settings)

    XYZ = spectral_to_XYZ(spd, cmfs)
    RGB = normalise(XYZ_to_sRGB(XYZ / 100))

    matplotlib.pyplot.subplot(212)

    settings = {'title': '{0} - Colour'.format(blackbody),
                'x_label': '{0}K'.format(temperature),
                'y_label': '',
                'aspect': None,
                'standalone': False}

    single_colour_plot(ColourParameter(name='', RGB=RGB), **settings)

    settings = {
        'standalone': True}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)
    return display(**settings)
Example #7
0
def multi_lightness_function_plot(functions=None, **kwargs):
    """
    Plots given *Lightness* functions.

    Parameters
    ----------
    functions : array_like, optional
        *Lightness* functions to plot.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Raises
    ------
    KeyError
        If one of the given *Lightness* function is not found in the factory
        *Lightness* functions.

    Examples
    --------
    >>> fs = ('CIE 1976', 'Wyszecki 1963')
    >>> multi_lightness_function_plot(fs)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if functions is None:
        functions = ('CIE 1976', 'Wyszecki 1963')

    samples = np.linspace(0, 100, 1000)
    for function in functions:
        function, name = LIGHTNESS_METHODS.get(function), function
        if function is None:
            raise KeyError(('"{0}" "Lightness" function not found in factory '
                            '"Lightness" functions: "{1}".').format(
                                name, sorted(LIGHTNESS_METHODS.keys())))

        pylab.plot(samples, [function(x) for x in samples],
                   label='{0}'.format(name),
                   linewidth=2)

    settings.update({
        'title':
        '{0} - Lightness Functions'.format(', '.join(functions)),
        'x_label':
        'Relative Luminance Y',
        'y_label':
        'Lightness',
        'x_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper left',
        'grid':
        True,
        'limits': (0, 100, 0, 100),
        'aspect':
        'equal'
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #8
0
def multi_lightness_function_plot(functions=None, **kwargs):
    """
    Plots given *Lightness* functions.

    Parameters
    ----------
    functions : array_like, optional
        *Lightness* functions to plot.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Raises
    ------
    KeyError
        If one of the given *Lightness* function is not found in the factory
        *Lightness* functions.

    Examples
    --------
    >>> fs = ('CIE 1976', 'Wyszecki 1963')
    >>> multi_lightness_function_plot(fs)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if functions is None:
        functions = ('CIE 1976', 'Wyszecki 1963')

    samples = np.linspace(0, 100, 1000)
    for function in functions:
        function, name = LIGHTNESS_METHODS.get(function), function
        if function is None:
            raise KeyError(('"{0}" "Lightness" function not found in factory '
                            '"Lightness" functions: "{1}".').format(
                                name, sorted(LIGHTNESS_METHODS.keys())))
        # TODO: Handle condition statement with metadata capabilities.
        pylab.plot(samples, (function(samples / 100) if name.lower() in (
            'fairchild 2010', 'fairchild 2011') else function(samples)),
                   label='{0}'.format(name),
                   linewidth=1)

    settings.update({
        'title':
        '{0} - Lightness Functions'.format(', '.join(functions)),
        'x_label':
        'Relative Luminance Y',
        'y_label':
        'Lightness',
        'x_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper left',
        'grid':
        True,
        'limits': (0, 100, 0, 100),
        'aspect':
        'equal'
    })
    settings.update(kwargs)

    return render(**settings)
Example #9
0
def single_spd_plot(spd,
                    cmfs='CIE 1931 2 Degree Standard Observer',
                    out_of_gamut_clipping=True,
                    **kwargs):
    """
    Plots given spectral power distribution.

    Parameters
    ----------
    spd : SpectralPowerDistribution
        Spectral power distribution to plot.
    out_of_gamut_clipping : bool, optional
        Whether to clip out of gamut colours otherwise, the colours will be
        offset by the absolute minimal colour leading to a rendering on
        gray background, less saturated and smoother.
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    References
    ----------
    -   :cite:`Spiker2015a`

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data = {
    ...     500: 0.0651,
    ...     520: 0.0705,
    ...     540: 0.0772,
    ...     560: 0.0870,
    ...     580: 0.1128,
    ...     600: 0.1360
    ... }
    >>> spd = SpectralPowerDistribution(data, name='Custom')
    >>> single_spd_plot(spd)  # doctest: +SKIP
    """

    axes = canvas(**kwargs).gca()

    cmfs = get_cmfs(cmfs)

    spd = spd.copy()
    spd.interpolator = LinearInterpolator
    wavelengths = cmfs.wavelengths[np.logical_and(
        cmfs.wavelengths >= max(min(cmfs.wavelengths), min(spd.wavelengths)),
        cmfs.wavelengths <= min(max(cmfs.wavelengths), max(spd.wavelengths)),
    )]
    values = spd[wavelengths]

    colours = XYZ_to_sRGB(
        wavelength_to_XYZ(wavelengths, cmfs),
        ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['E'],
        apply_encoding_cctf=False)

    if not out_of_gamut_clipping:
        colours += np.abs(np.min(colours))

    colours = DEFAULT_PLOTTING_ENCODING_CCTF(normalise_maximum(colours))

    x_min, x_max = min(wavelengths), max(wavelengths)
    y_min, y_max = 0, max(values)

    polygon = Polygon(np.vstack([
        (x_min, 0),
        tstack((wavelengths, values)),
        (x_max, 0),
    ]),
                      facecolor='none',
                      edgecolor='none')
    axes.add_patch(polygon)
    axes.bar(x=wavelengths,
             height=max(values),
             width=1,
             color=colours,
             align='edge',
             clip_path=polygon)
    axes.plot(wavelengths, values, color='black', linewidth=1)

    settings = {
        'title': '{0} - {1}'.format(spd.strict_name, cmfs.strict_name),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Power Distribution',
        'limits': (x_min, x_max, y_min, y_max),
        'x_tighten': True,
        'y_tighten': True
    }

    settings.update(kwargs)

    return render(**settings)
Example #10
0
def multi_spd_plot(spds,
                   cmfs='CIE 1931 2 Degree Standard Observer',
                   use_spds_colours=False,
                   normalise_spds_colours=False,
                   **kwargs):
    """
    Plots given spectral power distributions.

    Parameters
    ----------
    spds : list
        Spectral power distributions to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectrum creation.
    use_spds_colours : bool, optional
        Whether to use spectral power distributions colours.
    normalise_spds_colours : bool
        Whether to normalise spectral power distributions colours.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data_1 = {
    ...     500: 0.004900,
    ...     510: 0.009300,
    ...     520: 0.063270,
    ...     530: 0.165500,
    ...     540: 0.290400,
    ...     550: 0.433450,
    ...     560: 0.594500
    ... }
    >>> data_2 = {
    ...     500: 0.323000,
    ...     510: 0.503000,
    ...     520: 0.710000,
    ...     530: 0.862000,
    ...     540: 0.954000,
    ...     550: 0.994950,
    ...     560: 0.995000
    ... }
    >>> spd1 = SpectralPowerDistribution(data_1, name='Custom 1')
    >>> spd2 = SpectralPowerDistribution(data_2, name='Custom 2')
    >>> multi_spd_plot([spd1, spd2])  # doctest: +SKIP
    """

    canvas(**kwargs)

    cmfs = get_cmfs(cmfs)

    if use_spds_colours:
        illuminant = ILLUMINANTS_RELATIVE_SPDS['D65']

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for spd in spds:
        wavelengths, values = spd.wavelengths, spd.values

        shape = spd.shape
        x_limit_min.append(shape.start)
        x_limit_max.append(shape.end)
        y_limit_min.append(min(values))
        y_limit_max.append(max(values))

        if use_spds_colours:
            XYZ = spectral_to_XYZ(spd, cmfs, illuminant) / 100
            if normalise_spds_colours:
                XYZ = normalise_maximum(XYZ, clip=False)
            RGB = np.clip(XYZ_to_sRGB(XYZ), 0, 1)

            pylab.plot(wavelengths,
                       values,
                       color=RGB,
                       label=spd.strict_name,
                       linewidth=1)
        else:
            pylab.plot(wavelengths, values, label=spd.strict_name, linewidth=1)

    settings = {
        'x_label':
        'Wavelength $\\lambda$ (nm)',
        'y_label':
        'Spectral Power Distribution',
        'x_tighten':
        True,
        'y_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper left',
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max))
    }
    settings.update(kwargs)

    return render(**settings)
Example #11
0
def multi_cmfs_plot(cmfs=None, **kwargs):
    """
    Plots given colour matching functions.

    Parameters
    ----------
    cmfs : array_like, optional
        Colour matching functions to plot.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> cmfs = [
    ... 'CIE 1931 2 Degree Standard Observer',
    ... 'CIE 1964 10 Degree Standard Observer']
    >>> multi_cmfs_plot(cmfs)  # doctest: +SKIP
    """

    canvas(**kwargs)

    if cmfs is None:
        cmfs = ('CIE 1931 2 Degree Standard Observer',
                'CIE 1964 10 Degree Standard Observer')

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for i, rgb in enumerate([(1, 0, 0), (0, 1, 0), (0, 0, 1)]):
        for j, cmfs_i in enumerate(cmfs):
            cmfs_i = get_cmfs(cmfs_i)

            rgb = [reduce(lambda y, _: y * 0.5, range(j), x) for x in rgb]
            values = cmfs_i.values[:, i]

            shape = cmfs_i.shape
            x_limit_min.append(shape.start)
            x_limit_max.append(shape.end)
            y_limit_min.append(min(values))
            y_limit_max.append(max(values))

            pylab.plot(cmfs_i.wavelengths,
                       values,
                       color=rgb,
                       label=u'{0} - {1}'.format(cmfs_i.labels[i],
                                                 cmfs_i.strict_name),
                       linewidth=1)

    settings = {
        'title':
        '{0} - Colour Matching Functions'.format(', '.join(
            [get_cmfs(c).strict_name for c in cmfs])),
        'x_label':
        'Wavelength $\\lambda$ (nm)',
        'y_label':
        'Tristimulus Values',
        'x_tighten':
        True,
        'y_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper right',
        'grid':
        True,
        'y_axis_line':
        True,
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max))
    }
    settings.update(kwargs)

    return render(**settings)
Example #12
0
def CIE_1931_chromaticity_diagram_colours_plot(
        surface=1,
        samples=4096,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram* colours.

    Parameters
    ----------
    surface : numeric, optional
        Generated markers surface.
    samples : numeric, optional
        Samples count on one axis.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_colours_plot()  # doctest: +SKIP
    True
    """

    if is_scipy_installed(raise_exception=True):
        from scipy.spatial import Delaunay

        settings = {'figure_size': (64, 64)}
        settings.update(kwargs)

        canvas(**settings)

        cmfs = get_cmfs(cmfs)

        illuminant = DEFAULT_PLOTTING_ILLUMINANT

        triangulation = Delaunay(XYZ_to_xy(cmfs.values, illuminant),
                                 qhull_options='QJ')
        xx, yy = np.meshgrid(np.linspace(0, 1, samples),
                             np.linspace(0, 1, samples))
        xy = tstack((xx, yy))
        xy = xy[triangulation.find_simplex(xy) > 0]

        XYZ = xy_to_XYZ(xy)

        RGB = normalise(XYZ_to_sRGB(XYZ, illuminant), axis=-1)

        x_dot, y_dot = tsplit(xy)

        pylab.scatter(x_dot, y_dot, color=RGB, s=surface)

        settings.update({
            'x_ticker': False,
            'y_ticker': False,
            'bounding_box': (0, 1, 0, 1),
            'bbox_inches': 'tight',
            'pad_inches': 0
        })
        settings.update(kwargs)

        ax = matplotlib.pyplot.gca()
        matplotlib.pyplot.setp(ax, frame_on=False)

        boundaries(**settings)
        decorate(**settings)

        return display(**settings)
Example #13
0
def CIE_1960_UCS_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots the *CIE 1960 UCS Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1960_UCS_chromaticity_diagram_plot()  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    image = matplotlib.image.imread(
        os.path.join(
            PLOTTING_RESOURCES_DIRECTORY,
            'CIE_1960_UCS_Chromaticity_Diagram_{0}.png'.format(
                cmfs.name.replace(' ', '_'))))
    pylab.imshow(image, interpolation=None, extent=(0, 1, 0, 1))

    labels = (420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540,
              550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 680)

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    uv = UCS_to_uv(XYZ_to_UCS(cmfs.values))

    wavelengths_chromaticity_coordinates = dict(tuple(zip(wavelengths, uv)))

    pylab.plot(uv[..., 0], uv[..., 1], color='black', linewidth=2)
    pylab.plot((uv[-1][0], uv[0][0]), (uv[-1][1], uv[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        u, v = wavelengths_chromaticity_coordinates.get(label)
        pylab.plot(u, v, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates.get(right)[0] -
              wavelengths_chromaticity_coordinates.get(left)[0])
        dy = (wavelengths_chromaticity_coordinates.get(right)[1] -
              wavelengths_chromaticity_coordinates.get(left)[1])

        norme = lambda x: x / np.linalg.norm(x)

        uv = np.array([u, v])
        direction = np.array([-dy, dx])

        normal = (np.array([-dy, dx])
                  if np.dot(norme(uv - equal_energy), norme(direction)) > 0
                  else np.array([dy, -dx]))
        normal = norme(normal)
        normal /= 25

        pylab.plot((u, u + normal[0] * 0.75), (v, v + normal[1] * 0.75),
                   color='black',
                   linewidth=1.5)
        pylab.text(u + normal[0],
                   v + normal[1],
                   label,
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    ticks = np.arange(-10, 10, 0.1)

    pylab.xticks(ticks)
    pylab.yticks(ticks)

    settings.update({
        'title':
        'CIE 1960 UCS Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label':
        'CIE u',
        'y_label':
        'CIE v',
        'grid':
        True,
        'bounding_box': (0, 1, 0, 1),
        'bbox_inches':
        'tight',
        'pad_inches':
        0
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
def plot_grid(filename, data_points, grid, bbox_xystar, xystar=True):
    if not have_matplotlib or not have_colour_package:
        return

    print("Plotting the grid ...")

    plt.figure()
    # Draw a nice chromaticity diagram.
    clr.CIE_1931_chromaticity_diagram_plot(standalone=False)
    clr.canvas(figure_size=(7,7))

    # Show the sRGB gamut.
    color_space = clr.get_RGB_colourspace('sRGB')
    x = color_space.primaries[:,0].tolist()
    y = color_space.primaries[:,1].tolist()
    plt.fill(x, y, color='black', label='sRGB', fill=False)

    # Draw crosses into all internal grid cells.
    # for gridcell in grid:
    #     if len(gridcell.indices) > 0 and gridcell.inside:
    #         if xystar:
    #             pointx = sum([data_points[i].xystar[0] for i in gridcell.indices])
    #             pointy = sum([data_points[i].xystar[1] for i in gridcell.indices])
    #             pointx /= len(gridcell.indices)
    #             pointy /= len(gridcell.indices)
    #             (pointx, pointy) = Transform.xy_from_xystar((pointx, pointy))
    #             plt.plot(pointx, pointy, "x", color="black")
    #         else:
    #             pointx = sum([data_points[i].uv[0] for i in gridcell.indices])
    #             pointy = sum([data_points[i].uv[1] for i in gridcell.indices])
    #             pointx /= len(gridcell.indices)
    #             pointy /= len(gridcell.indices)
    #             (pointx, pointy) = Transform.xy_from_uv((pointx, pointy))
    #             plt.plot(pointx, pointy, "x", color="black")
 
    # Draw data points.
    for i, data_point in enumerate(data_points):
        if xystar:
            p = Transform.xy_from_xystar(data_point.xystar)
        else:
            p = Transform.xy_from_uv(data_point.uv)

        if data_point.equal_energy_white:
            plt.plot(p[0], p[1], "o", color="white", ms=4)
        elif data_point.broken:
            plt.plot(p[0], p[1], "o", color="red", ms=4)
        else:
            plt.plot(p[0], p[1], "o", color="green", ms=4)

        # Show grid point indices, for debugging.
        # plt.text(p[0]+0.01, p[1]-0.01, '{}'.format(i))

    bp0 = Transform.xy_from_xystar([bbox_xystar[0][0], bbox_xystar[0][1]])
    bp1 = Transform.xy_from_xystar([bbox_xystar[0][0], bbox_xystar[1][1]])
    bp2 = Transform.xy_from_xystar([bbox_xystar[1][0], bbox_xystar[1][1]])
    bp3 = Transform.xy_from_xystar([bbox_xystar[1][0], bbox_xystar[0][1]])
    plt.plot([bp0[0], bp1[0], bp2[0], bp3[0], bp0[0]],
             [bp0[1], bp1[1], bp2[1], bp3[1], bp0[1]],
             label="Grid Bounding Box")

    plt.xlabel('$x$')
    plt.ylabel('$y$')

    plt.legend()
    plt.savefig(filename)
Example #15
0
def CIE_1931_chromaticity_diagram_colours_plot(
        surface=1,
        samples=4096,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram* colours.

    Parameters
    ----------
    surface : numeric, optional
        Generated markers surface.
    samples : numeric, optional
        Samples count on one axis.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_colours_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (64, 64)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    triangulation = Delaunay(XYZ_to_xy(cmfs.values, illuminant),
                             qhull_options='QJ')
    xx, yy = np.meshgrid(np.linspace(0, 1, samples),
                         np.linspace(0, 1, samples))
    xy = tstack((xx, yy))
    xy = xy[triangulation.find_simplex(xy) > 0]

    XYZ = xy_to_XYZ(xy)

    RGB = normalise_maximum(XYZ_to_sRGB(XYZ, illuminant), axis=-1)

    x_dot, y_dot = tsplit(xy)

    pylab.scatter(x_dot, y_dot, color=RGB, s=surface)

    settings.update({
        'x_ticker': False,
        'y_ticker': False,
        'bounding_box': (0, 1, 0, 1)})
    settings.update(kwargs)

    ax = matplotlib.pyplot.gca()
    matplotlib.pyplot.setp(ax, frame_on=False)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #16
0
def blackbody_colours_plot(shape=SpectralShape(150, 12500, 50),
                           cmfs='CIE 1931 2 Degree Standard Observer',
                           **kwargs):
    """
    Plots blackbody colours.

    Parameters
    ----------
    shape : SpectralShape, optional
        Spectral shape to use as plot boundaries.
    cmfs : unicode, optional
        Standard observer colour matching functions.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> blackbody_colours_plot()  # doctest: +SKIP
    """

    axes = canvas(**kwargs).gca()

    cmfs = get_cmfs(cmfs)

    colours = []
    temperatures = []

    with suppress_warnings():
        for temperature in shape:
            spd = blackbody_spd(temperature, cmfs.shape)

            XYZ = spectral_to_XYZ(spd, cmfs)
            RGB = normalise_maximum(XYZ_to_sRGB(XYZ / 100))

            colours.append(RGB)
            temperatures.append(temperature)

    x_min, x_max = min(temperatures), max(temperatures)
    y_min, y_max = 0, 1

    axes.bar(x=temperatures,
             height=1,
             width=shape.interval,
             color=colours,
             align='edge')

    settings = {
        'title': 'Blackbody Colours',
        'x_label': 'Temperature K',
        'y_label': None,
        'limits': (x_min, x_max, y_min, y_max),
        'x_tighten': True,
        'y_tighten': True,
        'y_ticker': False
    }
    settings.update(kwargs)

    return render(**settings)
Example #17
0
def multi_cmfs_plot(cmfs=None, **kwargs):
    """
    Plots given colour matching functions.

    Parameters
    ----------
    cmfs : array_like, optional
        Colour matching functions to plot.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> cmfs = [
    ... 'CIE 1931 2 Degree Standard Observer',
    ... 'CIE 1964 10 Degree Standard Observer']
    >>> multi_cmfs_plot(cmfs)  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    if cmfs is None:
        cmfs = ('CIE 1931 2 Degree Standard Observer',
                'CIE 1964 10 Degree Standard Observer')

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for axis, rgb in (('x', (1, 0, 0)),
                      ('y', (0, 1, 0)),
                      ('z', (0, 0, 1))):
        for i, cmfs_i in enumerate(cmfs):
            cmfs_i = get_cmfs(cmfs_i)

            rgb = [reduce(lambda y, _: y * 0.5, range(i), x)  # noqa
                   for x in rgb]
            wavelengths, values = tuple(
                zip(*[(key, value) for key, value in getattr(cmfs_i, axis)]))

            shape = cmfs_i.shape
            x_limit_min.append(shape.start)
            x_limit_max.append(shape.end)
            y_limit_min.append(min(values))
            y_limit_max.append(max(values))

            pylab.plot(wavelengths,
                       values,
                       color=rgb,
                       label=u'{0} - {1}'.format(
                           cmfs_i.labels.get(axis), cmfs_i.title),
                       linewidth=2)

    settings = {
        'title': '{0} - Colour Matching Functions'.format(', '.join(
            [get_cmfs(c).title for c in cmfs])),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Tristimulus Values',
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper right',
        'grid': True,
        'y_axis_line': True,
        'limits': (min(x_limit_min), max(x_limit_max),
                   min(y_limit_min), max(y_limit_max))}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #18
0
def CIE_1931_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_plot()  # doctest: +SKIP
    True

    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = CHROMATICITY_DIAGRAM_DEFAULT_ILLUMINANT

    image = matplotlib.image.imread(
        os.path.join(PLOTTING_RESOURCES_DIRECTORY,
                     'CIE_1931_Chromaticity_Diagram_{0}.png'.format(
                         cmfs.name.replace(' ', '_'))))
    pylab.imshow(image, interpolation=None, extent=(0, 1, 0, 1))

    labels = (
        390, 460, 470, 480, 490, 500, 510, 520, 540, 560, 580, 600, 620, 700)

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    xy = XYZ_to_xy(cmfs.values, illuminant)

    wavelengths_chromaticity_coordinates = dict(tuple(zip(wavelengths, xy)))

    pylab.plot(xy[..., 0], xy[..., 1], color='black', linewidth=2)
    pylab.plot((xy[-1][0], xy[0][0]),
               (xy[-1][1], xy[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        x, y = wavelengths_chromaticity_coordinates.get(label)
        pylab.plot(x, y, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else
                 wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates.get(right)[0] -
              wavelengths_chromaticity_coordinates.get(left)[0])
        dy = (wavelengths_chromaticity_coordinates.get(right)[1] -
              wavelengths_chromaticity_coordinates.get(left)[1])

        norme = lambda x: x / np.linalg.norm(x)

        xy = np.array([x, y])
        direction = np.array([-dy, dx])

        normal = (np.array([-dy, dx])
                  if np.dot(norme(xy - equal_energy),
                            norme(direction)) > 0 else
                  np.array([dy, -dx]))
        normal = norme(normal)
        normal /= 25

        pylab.plot((x, x + normal[0] * 0.75),
                   (y, y + normal[1] * 0.75),
                   color='black',
                   linewidth=1.5)
        pylab.text(x + normal[0],
                   y + normal[1],
                   label,
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    ticks = np.arange(-10, 10, 0.1)

    pylab.xticks(ticks)
    pylab.yticks(ticks)

    settings.update({
        'title': 'CIE 1931 Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label': 'CIE x',
        'y_label': 'CIE y',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'bounding_box': (0, 1, 0, 1),
        'bbox_inches': 'tight',
        'pad_inches': 0})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #19
0
def multi_spd_plot(spds,
                   cmfs='CIE 1931 2 Degree Standard Observer',
                   use_spds_colours=False,
                   normalise_spds_colours=False,
                   **kwargs):
    """
    Plots given spectral power distributions.

    Parameters
    ----------
    spds : list
        Spectral power distributions to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectrum creation.
    use_spds_colours : bool, optional
        Use spectral power distributions colours.
    normalise_spds_colours : bool
        Should spectral power distributions colours normalised.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data1 = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> data2 = {400: 0.134, 420: 0.789, 440: 1.289}
    >>> spd1 = SpectralPowerDistribution('Custom1', data1)
    >>> spd2 = SpectralPowerDistribution('Custom2', data2)
    >>> multi_spd_plot([spd1, spd2])  # doctest: +SKIP
    """

    canvas(**kwargs)

    cmfs = get_cmfs(cmfs)

    if use_spds_colours:
        illuminant = ILLUMINANTS_RELATIVE_SPDS.get('D65')

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for spd in spds:
        wavelengths, values = tuple(zip(*spd.items))

        shape = spd.shape
        x_limit_min.append(shape.start)
        x_limit_max.append(shape.end)
        y_limit_min.append(min(values))
        y_limit_max.append(max(values))

        if use_spds_colours:
            XYZ = spectral_to_XYZ(spd, cmfs, illuminant) / 100
            if normalise_spds_colours:
                XYZ = normalise_maximum(XYZ, clip=False)
            RGB = np.clip(XYZ_to_sRGB(XYZ), 0, 1)

            pylab.plot(wavelengths,
                       values,
                       color=RGB,
                       label=spd.title,
                       linewidth=2)
        else:
            pylab.plot(wavelengths, values, label=spd.title, linewidth=2)

    settings = {
        'x_label':
        'Wavelength $\\lambda$ (nm)',
        'y_label':
        'Spectral Power Distribution',
        'x_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper left',
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max))
    }
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #20
0
def CIE_1931_chromaticity_diagram_colours_plot(
        surface=1,
        samples=4096,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram* colours.

    Parameters
    ----------
    surface : numeric, optional
        Generated markers surface.
    samples : numeric, optional
        Samples count on one axis.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_colours_plot()  # doctest: +SKIP
    True
    """

    if is_scipy_installed(raise_exception=True):
        from scipy.spatial import Delaunay

        settings = {'figure_size': (64, 64)}
        settings.update(kwargs)

        canvas(**settings)

        cmfs = get_cmfs(cmfs)

        illuminant = CHROMATICITY_DIAGRAM_DEFAULT_ILLUMINANT

        triangulation = Delaunay(XYZ_to_xy(cmfs.values, illuminant),
                                 qhull_options='QJ')
        xx, yy = np.meshgrid(np.linspace(0, 1, samples),
                             np.linspace(0, 1, samples))
        xy = tstack((xx, yy))
        xy = xy[triangulation.find_simplex(xy) > 0]

        XYZ = xy_to_XYZ(xy)

        RGB = normalise(XYZ_to_sRGB(XYZ, illuminant), axis=-1)

        x_dot, y_dot = tsplit(xy)

        pylab.scatter(x_dot, y_dot, color=RGB, s=surface)

        settings.update({
            'no_ticks': True,
            'bounding_box': (0, 1, 0, 1),
            'bbox_inches': 'tight',
            'pad_inches': 0})
        settings.update(kwargs)

        ax = matplotlib.pyplot.gca()
        matplotlib.pyplot.setp(ax, frame_on=False)

        boundaries(**settings)
        decorate(**settings)

        return display(**settings)
Example #21
0
def colour_checker_plot(colour_checker='ColorChecker 2005', **kwargs):
    """
    Plots given colour checker.

    Parameters
    ----------
    colour_checker : unicode, optional
        Color checker name.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.
    width : numeric, optional
        {:func:`multi_colour_plot`},
        Colour polygon width.
    height : numeric, optional
        {:func:`multi_colour_plot`},
        Colour polygon height.
    spacing : numeric, optional
        {:func:`multi_colour_plot`},
        Colour polygons spacing.
    across : int, optional
        {:func:`multi_colour_plot`},
        Colour polygons count per row.
    text_display : bool, optional
        {:func:`multi_colour_plot`},
        Display colour text.
    text_size : numeric, optional
        {:func:`multi_colour_plot`},
        Colour text size.
    text_offset : numeric, optional
        {:func:`multi_colour_plot`},
        Colour text offset.

    Returns
    -------
    Figure
        Current figure or None.

    Raises
    ------
    KeyError
        If the given colour rendition chart is not found in the factory colour
        rendition charts.

    Examples
    --------
    >>> colour_checker_plot()  # doctest: +SKIP
    """

    canvas(**kwargs)

    colour_checker, name = COLOURCHECKERS.get(colour_checker), colour_checker
    if colour_checker is None:
        raise KeyError(('Colour checker "{0}" not found in '
                        'factory colour checkers: "{1}".').format(
                            name, sorted(COLOURCHECKERS.keys())))

    _name, data, illuminant = colour_checker
    colour_parameters = []
    for _index, label, xyY in data:
        XYZ = xyY_to_XYZ(xyY)
        RGB = XYZ_to_sRGB(XYZ, illuminant)

        colour_parameters.append(
            ColourParameter(label.title(), np.clip(np.ravel(RGB), 0, 1)))

    background_colour = '0.1'
    width = height = 1.0
    spacing = 0.25
    across = 6

    settings = {
        'standalone': False,
        'width': width,
        'height': height,
        'spacing': spacing,
        'across': across,
        'text_size': 8,
        'background_colour': background_colour,
        'margins': (-0.125, 0.125, -0.5, 0.125)
    }
    settings.update(kwargs)

    multi_colour_plot(colour_parameters, **settings)

    text_x = width * (across / 2) + (across * (spacing / 2)) - spacing / 2
    text_y = -(len(colour_parameters) / across + spacing / 2)

    pylab.text(
        text_x,
        text_y,
        '{0} - {1} - Colour Rendition Chart'.format(
            name, RGB_COLOURSPACES['sRGB'].name),
        color='0.95',
        clip_on=True,
        ha='center')

    settings.update({
        'title': name,
        'facecolor': background_colour,
        'edgecolor': None,
        'standalone': True
    })

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #22
0
def the_blue_sky_plot(cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots the blue sky.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> the_blue_sky_plot()  # doctest: +SKIP
    """

    canvas(**kwargs)

    cmfs, name = get_cmfs(cmfs), cmfs

    ASTM_G_173_spd = ASTM_G_173_ETR.copy()
    rayleigh_spd = rayleigh_scattering_spd()
    ASTM_G_173_spd.align(rayleigh_spd.shape)

    spd = rayleigh_spd * ASTM_G_173_spd

    matplotlib.pyplot.subplots_adjust(hspace=0.4)

    matplotlib.pyplot.figure(1)
    matplotlib.pyplot.subplot(211)

    settings = {
        'title': 'The Blue Sky - Synthetic Spectral Power Distribution',
        'y_label': u'W / m-2 / nm-1',
        'standalone': False
    }
    settings.update(kwargs)

    single_spd_plot(spd, name, **settings)

    matplotlib.pyplot.subplot(212)

    settings = {
        'title':
            'The Blue Sky - Colour',
        'x_label': ('The sky is blue because molecules in the atmosphere '
                    'scatter shorter wavelengths more than longer ones.\n'
                    'The synthetic spectral power distribution is computed as '
                    'follows: '
                    '(ASTM G-173 ETR * Standard Air Rayleigh Scattering).'),
        'y_label':
            '',
        'aspect':
            None,
        'standalone':
            False
    }

    blue_sky_color = XYZ_to_sRGB(spectral_to_XYZ(spd))
    single_colour_swatch_plot(
        ColourSwatch('', normalise_maximum(blue_sky_color)), **settings)

    settings = {'standalone': True}
    settings.update(kwargs)

    return render(**settings)
Example #23
0
def colour_checker_plot(colour_checker='ColorChecker 2005', **kwargs):
    """
    Plots given colour checker.

    Parameters
    ----------
    colour_checker : unicode, optional
        Color checker name.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Raises
    ------
    KeyError
        If the given colour rendition chart is not found in the factory colour
        rendition charts.

    Examples
    --------
    >>> colour_checker_plot()  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    colour_checker, name = COLOURCHECKERS.get(colour_checker), colour_checker
    if colour_checker is None:
        raise KeyError(
            ('Colour checker "{0}" not found in '
             'factory colour checkers: "{1}".').format(
                name, sorted(COLOURCHECKERS.keys())))

    _name, data, illuminant = colour_checker
    colour_parameters = []
    for _index, label, x, y, Y in data:
        XYZ = xyY_to_XYZ((x, y, Y))
        RGB = XYZ_to_sRGB(XYZ, illuminant)

        colour_parameters.append(
            ColourParameter(label.title(), np.clip(np.ravel(RGB), 0, 1)))

    background_colour = '0.1'
    matplotlib.pyplot.gca().patch.set_facecolor(background_colour)

    width = height = 1.0
    spacing = 0.25
    across = 6

    settings = {
        'standalone': False,
        'width': width,
        'height': height,
        'spacing': spacing,
        'across': across,
        'text_size': 8,
        'margins': (-0.125, 0.125, -0.5, 0.125)}
    settings.update(kwargs)

    multi_colour_plot(colour_parameters, **settings)

    text_x = width * (across / 2) + (across * (spacing / 2)) - spacing / 2
    text_y = -(len(colour_parameters) / across + spacing / 2)

    pylab.text(text_x,
               text_y,
               '{0} - {1} - Colour Rendition Chart'.format(
                   name, RGB_COLOURSPACES.get('sRGB').name),
               color='0.95',
               clip_on=True,
               ha='center')

    settings.update({
        'title': name,
        'facecolor': background_colour,
        'edgecolor': None,
        'standalone': True})

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #24
0
def corresponding_chromaticities_prediction_plot(
        experiment=1,
        model='Von Kries',
        transform='CAT02',
        **kwargs):
    """
    Plots given chromatic adaptation model corresponding chromaticities
    prediction.

    Parameters
    ----------
    experiment : int, optional
        Corresponding chromaticities prediction experiment number.
    model : unicode, optional
        Corresponding chromaticities prediction model name.
    transform : unicode, optional
        Transformation to use with Von Kries chromatic adaptation model.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> corresponding_chromaticities_prediction_plot()  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    model, name = (
        get_corresponding_chromaticities_prediction_model(model), model)

    settings.update({
        'title': (('Corresponding Chromaticities Prediction\n{0} ({1}) - '
                   'Experiment {2}\nCIE 1976 UCS Chromaticity Diagram').format(
            name, transform, experiment)
            if name.lower() in ('von kries', 'vonkries') else
            ('Corresponding Chromaticities Prediction\n{0} - '
                'Experiment {1}\nCIE 1976 UCS Chromaticity Diagram').format(
                    name, experiment)),
        'standalone': False})
    settings.update(kwargs)

    CIE_1976_UCS_chromaticity_diagram_plot(**settings)

    results = model(experiment, transform=transform)

    for result in results:
        name, uvp_t, uvp_m, uvp_p = result
        pylab.arrow(uvp_t[0],
                    uvp_t[1],
                    uvp_p[0] - uvp_t[0] - 0.1 * (uvp_p[0] - uvp_t[0]),
                    uvp_p[1] - uvp_t[1] - 0.1 * (uvp_p[1] - uvp_t[1]),
                    head_width=0.005,
                    head_length=0.005,
                    linewidth=0.5,
                    color='black')
        pylab.plot(uvp_t[0], uvp_t[1], 'o', color='white')
        pylab.plot(uvp_m[0], uvp_m[1], '^', color='white')
        pylab.plot(uvp_p[0], uvp_p[1], '^', color='black')
    settings.update({
        'x_tighten': True,
        'y_tighten': True,
        'limits': (-0.1, 0.7, -0.1, 0.7),
        'standalone': True})

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #25
0
def multi_transfer_function_plot(colourspaces=None,
                                 inverse=False, **kwargs):
    """
    Plots given colourspaces transfer functions.

    Parameters
    ----------
    colourspaces : list, optional
        Colourspaces transfer functions to plot.
    inverse : bool
        Plot inverse transfer functions.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> multi_transfer_function_plot(['sRGB', 'Rec. 709'])  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ['sRGB', 'Rec. 709']

    samples = np.linspace(0, 1, 1000)
    for colourspace in colourspaces:
        colourspace = get_RGB_colourspace(colourspace)

        RGBs = np.array([colourspace.inverse_transfer_function(x)
                         if inverse else
                         colourspace.transfer_function(x)
                         for x in samples])
        pylab.plot(samples,
                   RGBs,
                   label=u'{0}'.format(colourspace.name),
                   linewidth=2)

    settings.update({
        'title': '{0} - Transfer Functions'.format(
            ', '.join(colourspaces)),
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper left',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'limits': (0, 1, 0, 1),
        'aspect': 'equal'})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #26
0
def multi_munsell_value_function_plot(
        functions=None,
        **kwargs):
    """
    Plots given *Munsell* value functions.

    Parameters
    ----------
    functions : array_like, optional
        *Munsell* value functions to plot.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Raises
    ------
    KeyError
        If one of the given *Munsell* value function is not found in the
        factory *Munsell* value functions.

    Examples
    --------
    >>> fs = ('ASTM D1535-08', 'McCamy 1987')
    >>> multi_munsell_value_function_plot(fs)  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if functions is None:
        functions = ('ASTM D1535-08',
                     'McCamy 1987')

    samples = np.linspace(0, 100, 1000)
    for function in functions:
        function, name = MUNSELL_VALUE_METHODS.get(function), function
        if function is None:
            raise KeyError(
                ('"{0}" "Munsell" value function not found in '
                 'factory "Munsell" value functions: "{1}".').format(
                    name, sorted(MUNSELL_VALUE_METHODS.keys())))

        pylab.plot(samples,
                   [function(x) for x in samples],
                   label=u'{0}'.format(name),
                   linewidth=2)

    settings.update({
        'title': '{0} - Munsell Functions'.format(', '.join(functions)),
        'x_label': 'Luminance Y',
        'y_label': 'Munsell Value V',
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper left',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'bounding_box': (0, 100, 0, 10),
        'aspect': 10})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #27
0
def tonemapping_operator_image_plot(
        image,
        luminance_function,
        log_scale=False,
        encoding_cctf=DEFAULT_PLOTTING_ENCODING_CCTF,
        **kwargs):
    """
    Plots given tonemapped image with superimposed luminance mapping function.

    Parameters
    ----------
    image : array_like
         Tonemapped image to plot.
    luminance_function : callable
        Luminance mapping function.
    log_scale : bool, optional
        Use a log scale for plotting the luminance mapping function.
    encoding_cctf : callable, optional
        Encoding colour component transfer function / opto-electronic
        transfer function used for plotting.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    bool
        Definition success.
    """

    shape = image.shape
    limits = [0, 1, 0, 1]

    image = np.clip(encoding_cctf(image), 0, 1)
    pylab.imshow(image,
                 aspect=shape[0] / shape[1],
                 extent=limits,
                 interpolation='nearest')

    pylab.plot(np.linspace(0, 1, len(luminance_function)),
               luminance_function,
               color='red')

    settings = {
        'figure_size': (8, 8),
        'x_label': 'Input Luminance',
        'y_label': 'Output Luminance',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'x_tighten': True,
        'y_tighten': True,
        'limits': limits
    }
    settings.update(kwargs)

    if log_scale:
        settings.update({
            'x_label':
            '$log_2$ Input Luminance',
            'x_ticker_locator':
            matplotlib.ticker.AutoMinorLocator(0.5)
        })
        matplotlib.pyplot.gca().set_xscale('log', basex=2)
        matplotlib.pyplot.gca().xaxis.set_major_formatter(
            matplotlib.ticker.ScalarFormatter())

    canvas(**settings)
    decorate(**settings)
    boundaries(**settings)

    return display(**settings)
Example #28
0
def RGB_colourspaces_CIE_1960_UCS_chromaticity_diagram_plot(
        colourspaces=None,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots given *RGB* colourspaces in *CIE 1960 UCS Chromaticity Diagram*.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_CIE_1960_UCS_chromaticity_diagram_plot(
    ...     c)  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut')

    cmfs, name = get_cmfs(cmfs), cmfs

    settings = {
        'title': '{0} - {1} - CIE 1960 UCS Chromaticity Diagram'.format(
            ', '.join(colourspaces), name),
        'standalone': False}
    settings.update(kwargs)

    CIE_1960_UCS_chromaticity_diagram_plot(**settings)

    x_limit_min, x_limit_max = [-0.1], [0.7]
    y_limit_min, y_limit_max = [-0.2], [0.6]

    settings = {'colour_cycle_map': 'rainbow',
                'colour_cycle_count': len(colourspaces)}
    settings.update(kwargs)

    cycle = colour_cycle(**settings)

    for colourspace in colourspaces:
        if colourspace == 'Pointer Gamut':
            uv = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(POINTER_GAMUT_BOUNDARIES)))
            alpha_p, colour_p = 0.85, '0.95'
            pylab.plot(uv[..., 0],
                       uv[..., 1],
                       label='Pointer\'s Gamut',
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)
            pylab.plot((uv[-1][0], uv[0][0]),
                       (uv[-1][1], uv[0][1]),
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)

            XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                             POINTER_GAMUT_ILLUMINANT)
            uv = UCS_to_uv(XYZ_to_UCS(XYZ))
            pylab.scatter(uv[..., 0],
                          uv[..., 1],
                          alpha=alpha_p / 2,
                          color=colour_p,
                          marker='+')

        else:
            colourspace, name = get_RGB_colourspace(colourspace), colourspace

            r, g, b, _a = next(cycle)

            # RGB colourspaces such as *ACES2065-1* have primaries with
            # chromaticity coordinates set to 0 thus we prevent nan from being
            # yield by zero division in later colour transformations.
            primaries = np.where(colourspace.primaries == 0,
                                 EPSILON,
                                 colourspace.primaries)

            primaries = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(primaries)))
            whitepoint = UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(
                colourspace.whitepoint)))

            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       color=(r, g, b),
                       label=colourspace.name,
                       linewidth=2)
            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       'o',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[0, 0], primaries[1, 0]),
                       (primaries[0, 1], primaries[1, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[1, 0], primaries[2, 0]),
                       (primaries[1, 1], primaries[2, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[2, 0], primaries[0, 0]),
                       (primaries[2, 1], primaries[0, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)

            x_limit_min.append(np.amin(primaries[..., 0]) - 0.1)
            y_limit_min.append(np.amin(primaries[..., 1]) - 0.1)
            x_limit_max.append(np.amax(primaries[..., 0]) + 0.1)
            y_limit_max.append(np.amax(primaries[..., 1]) + 0.1)

    settings.update({
        'legend': True,
        'legend_location': 'upper right',
        'x_tighten': True,
        'y_tighten': True,
        'limits': (min(x_limit_min), max(x_limit_max),
                   min(y_limit_min), max(y_limit_max)),
        'standalone': True})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #29
0
def multi_cctf_plot(colourspaces=None, decoding_cctf=False, **kwargs):
    """
    Plots given colourspaces colour component transfer functions.

    Parameters
    ----------
    colourspaces : array_like, optional
        Colourspaces colour component transfer function to plot.
    decoding_cctf : bool
        Plot decoding colour component transfer function instead.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> multi_cctf_plot(['Rec. 709', 'sRGB'])  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'sRGB')

    samples = np.linspace(0, 1, 1000)
    for colourspace in colourspaces:
        colourspace = get_RGB_colourspace(colourspace)

        RGBs = (colourspace.decoding_cctf(samples)
                if decoding_cctf else colourspace.encoding_cctf(samples))

        pylab.plot(samples,
                   RGBs,
                   label=u'{0}'.format(colourspace.name),
                   linewidth=2)

    settings.update({
        'title':
        '{0} - {1} CCTFs'.format(', '.join(colourspaces),
                                 'Decoding' if decoding_cctf else 'Encoding'),
        'x_tighten':
        True,
        'x_label':
        'Signal Value' if decoding_cctf else 'Tristimulus Value',
        'y_label':
        'Tristimulus Value' if decoding_cctf else 'Signal Value',
        'legend':
        True,
        'legend_location':
        'upper left',
        'grid':
        True,
        'limits': (0, 1, 0, 1),
        'aspect':
        'equal'
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #30
0
def RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot(
        colourspaces=None,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots given *RGB* colourspaces in *CIE 1976 UCS Chromaticity Diagram*.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot(
    ...     c)  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut')

    cmfs, name = get_cmfs(cmfs), cmfs

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    settings = {
        'title': '{0} - {1} - CIE 1976 UCS Chromaticity Diagram'.format(
            ', '.join(colourspaces), name),
        'standalone': False}
    settings.update(kwargs)

    CIE_1976_UCS_chromaticity_diagram_plot(**settings)

    x_limit_min, x_limit_max = [-0.1], [0.7]
    y_limit_min, y_limit_max = [-0.1], [0.7]

    settings = {'colour_cycle_map': 'rainbow',
                'colour_cycle_count': len(colourspaces)}
    settings.update(kwargs)

    cycle = colour_cycle(**settings)

    for colourspace in colourspaces:
        if colourspace == 'Pointer Gamut':
            uv = Luv_to_uv(XYZ_to_Luv(xy_to_XYZ(
                POINTER_GAMUT_BOUNDARIES), illuminant), illuminant)
            alpha_p, colour_p = 0.85, '0.95'
            pylab.plot(uv[..., 0],
                       uv[..., 1],
                       label='Pointer\'s Gamut',
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)
            pylab.plot((uv[-1][0], uv[0][0]),
                       (uv[-1][1], uv[0][1]),
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)

            XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                             POINTER_GAMUT_ILLUMINANT)
            uv = Luv_to_uv(XYZ_to_Luv(XYZ, illuminant), illuminant)
            pylab.scatter(uv[..., 0],
                          uv[..., 1],
                          alpha=alpha_p / 2,
                          color=colour_p,
                          marker='+')

        else:
            colourspace, name = get_RGB_colourspace(colourspace), colourspace

            r, g, b, _a = next(cycle)

            # RGB colourspaces such as *ACES2065-1* have primaries with
            # chromaticity coordinates set to 0 thus we prevent nan from being
            # yield by zero division in later colour transformations.
            primaries = np.where(colourspace.primaries == 0,
                                 EPSILON,
                                 colourspace.primaries)

            primaries = Luv_to_uv(XYZ_to_Luv(xy_to_XYZ(
                primaries), illuminant), illuminant)
            whitepoint = Luv_to_uv(XYZ_to_Luv(xy_to_XYZ(
                colourspace.whitepoint), illuminant), illuminant)

            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       color=(r, g, b),
                       label=colourspace.name,
                       linewidth=2)
            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       'o',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[0, 0], primaries[1, 0]),
                       (primaries[0, 1], primaries[1, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[1, 0], primaries[2, 0]),
                       (primaries[1, 1], primaries[2, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[2, 0], primaries[0, 0]),
                       (primaries[2, 1], primaries[0, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)

            x_limit_min.append(np.amin(primaries[..., 0]) - 0.1)
            y_limit_min.append(np.amin(primaries[..., 1]) - 0.1)
            x_limit_max.append(np.amax(primaries[..., 0]) + 0.1)
            y_limit_max.append(np.amax(primaries[..., 1]) + 0.1)

    settings.update({
        'legend': True,
        'legend_location': 'upper right',
        'x_tighten': True,
        'y_tighten': True,
        'limits': (min(x_limit_min), max(x_limit_max),
                   min(y_limit_min), max(y_limit_max)),
        'standalone': True})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #31
0
def CIE_1976_UCS_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer',
        show_diagram_colours=True,
        **kwargs):
    """
    Plots the *CIE 1976 UCS Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    show_diagram_colours : bool, optional
        Display the chromaticity diagram background colours.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> CIE_1976_UCS_chromaticity_diagram_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    if show_diagram_colours:
        image = matplotlib.image.imread(
            os.path.join(PLOTTING_RESOURCES_DIRECTORY,
                         'CIE_1976_UCS_Chromaticity_Diagram_{0}.png'.format(
                             cmfs.name.replace(' ', '_'))))
        pylab.imshow(image, interpolation=None, extent=(0, 1, 0, 1))

    labels = (420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530,
              540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 680)

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    uv = Luv_to_uv(XYZ_to_Luv(cmfs.values, illuminant), illuminant)

    wavelengths_chromaticity_coordinates = dict(zip(wavelengths, uv))

    pylab.plot(uv[..., 0], uv[..., 1], color='black', linewidth=2)
    pylab.plot((uv[-1][0], uv[0][0]),
               (uv[-1][1], uv[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        u, v = wavelengths_chromaticity_coordinates.get(label)
        pylab.plot(u, v, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else
                 wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates.get(right)[0] -
              wavelengths_chromaticity_coordinates.get(left)[0])
        dy = (wavelengths_chromaticity_coordinates.get(right)[1] -
              wavelengths_chromaticity_coordinates.get(left)[1])

        uv = np.array([u, v])
        direction = np.array([-dy, dx])

        normal = (np.array([-dy, dx])
                  if np.dot(normalise_vector(uv - equal_energy),
                            normalise_vector(direction)) > 0 else
                  np.array([dy, -dx]))
        normal = normalise_vector(normal)
        normal /= 25

        pylab.plot((u, u + normal[0] * 0.75),
                   (v, v + normal[1] * 0.75),
                   color='black',
                   linewidth=1.5)
        pylab.text(u + normal[0],
                   v + normal[1],
                   label,
                   color='black',
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    ticks = np.arange(-10, 10, 0.1)

    pylab.xticks(ticks)
    pylab.yticks(ticks)

    settings.update({
        'title': 'CIE 1976 UCS Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label': 'CIE u\'',
        'y_label': 'CIE v\'',
        'grid': True,
        'bounding_box': (0, 1, 0, 1)})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #32
0
def multi_conversion_function_plot(colourspaces=None,
                                   EOCF=False,
                                   **kwargs):
    """
    Plots given colourspaces opto-electronic conversion functions.

    Parameters
    ----------
    colourspaces : array_like, optional
        Colourspaces opto-electronic conversion functions to plot.
    EOCF : bool
        Plot electro-optical conversion functions instead.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> multi_conversion_function_plot(['Rec. 709', 'sRGB'])  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'sRGB')

    samples = np.linspace(0, 1, 1000)
    for colourspace in colourspaces:
        colourspace = get_RGB_colourspace(colourspace)

        RGBs = colourspace.EOCF(samples) if EOCF else colourspace.OECF(samples)

        pylab.plot(samples,
                   RGBs,
                   label=u'{0}'.format(colourspace.name),
                   linewidth=2)

    settings.update({
        'title': '{0} - {1} Conversion Functions'.format(
            ', '.join(colourspaces),
            'Electro-Optical' if EOCF else 'Opto-Electronic'),
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper left',
        'grid': True,
        'limits': (0, 1, 0, 1),
        'aspect': 'equal'})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #33
0
def multi_spd_plot(spds,
                   cmfs='CIE 1931 2 Degree Standard Observer',
                   use_spds_colours=False,
                   normalise_spds_colours=False,
                   **kwargs):
    """
    Plots given spectral power distributions.

    Parameters
    ----------
    spds : list
        Spectral power distributions to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectrum creation.
    use_spds_colours : bool, optional
        Use spectral power distributions colours.
    normalise_spds_colours : bool
        Should spectral power distributions colours normalised.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data1 = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> data2 = {400: 0.134, 420: 0.789, 440: 1.289}
    >>> spd1 = SpectralPowerDistribution('Custom1', data1)
    >>> spd2 = SpectralPowerDistribution('Custom2', data2)
    >>> multi_spd_plot([spd1, spd2])  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    cmfs = get_cmfs(cmfs)

    if use_spds_colours:
        illuminant = ILLUMINANTS_RELATIVE_SPDS.get('D65')

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for spd in spds:
        wavelengths, values = tuple(zip(*spd.items))

        shape = spd.shape
        x_limit_min.append(shape.start)
        x_limit_max.append(shape.end)
        y_limit_min.append(min(values))
        y_limit_max.append(max(values))

        if use_spds_colours:
            XYZ = spectral_to_XYZ(spd, cmfs, illuminant) / 100
            if normalise_spds_colours:
                XYZ = normalise(XYZ, clip=False)
            RGB = np.clip(XYZ_to_sRGB(XYZ), 0, 1)

            pylab.plot(wavelengths, values, color=RGB, label=spd.title,
                       linewidth=2)
        else:
            pylab.plot(wavelengths, values, label=spd.title, linewidth=2)

    settings = {
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Power Distribution',
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper left',
        'limits': (min(x_limit_min), max(x_limit_max),
                   min(y_limit_min), max(y_limit_max))}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #34
0
def multi_munsell_value_function_plot(functions=None, **kwargs):
    """
    Plots given *Munsell* value functions.

    Parameters
    ----------
    functions : array_like, optional
        *Munsell* value functions to plot.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definition.

    Returns
    -------
    Figure
        Current figure or None.

    Raises
    ------
    KeyError
        If one of the given *Munsell* value function is not found in the
        factory *Munsell* value functions.

    Examples
    --------
    >>> fs = ('ASTM D1535-08', 'McCamy 1987')
    >>> multi_munsell_value_function_plot(fs)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if functions is None:
        functions = ('ASTM D1535-08', 'McCamy 1987')

    samples = np.linspace(0, 100, 1000)
    for function in functions:
        function, name = MUNSELL_VALUE_METHODS.get(function), function
        if function is None:
            raise KeyError(
                ('"{0}" "Munsell" value function not found in '
                 'factory "Munsell" value functions: "{1}".').format(
                     name, sorted(MUNSELL_VALUE_METHODS.keys())))

        pylab.plot(samples, [function(x) for x in samples],
                   label=u'{0}'.format(name),
                   linewidth=1)

    settings.update({
        'title':
        '{0} - Munsell Functions'.format(', '.join(functions)),
        'x_label':
        'Luminance Y',
        'y_label':
        'Munsell Value V',
        'x_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper left',
        'grid':
        True,
        'bounding_box': (0, 100, 0, 10),
        'aspect':
        10
    })
    settings.update(kwargs)

    return render(**settings)
Example #35
0
def multi_lightness_function_plot(functions=None, **kwargs):
    """
    Plots given *Lightness* functions.

    Parameters
    ----------
    functions : array_like, optional
        *Lightness* functions to plot.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Raises
    ------
    KeyError
        If one of the given *Lightness* function is not found in the factory
        *Lightness* functions.

    Examples
    --------
    >>> fs = ('CIE 1976', 'Wyszecki 1963')
    >>> multi_lightness_function_plot(fs)  # doctest: +SKIP
    True
    """

    settings = {
        'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if functions is None:
        functions = ('CIE 1976', 'Wyszecki 1963')

    samples = np.linspace(0, 100, 1000)
    for function in functions:
        function, name = LIGHTNESS_METHODS.get(function), function
        if function is None:
            raise KeyError(
                ('"{0}" "Lightness" function not found in factory '
                 '"Lightness" functions: "{1}".').format(
                    name, sorted(LIGHTNESS_METHODS.keys())))

        pylab.plot(samples,
                   [function(x) for x in samples],
                   label='{0}'.format(name),
                   linewidth=2)

    settings.update({
        'title': '{0} - Lightness Functions'.format(', '.join(functions)),
        'x_label': 'Luminance Y',
        'y_label': 'Lightness L*',
        'x_tighten': True,
        'legend': True,
        'legend_location': 'upper left',
        'grid': True,
        'limits': (0, 100, 0, 100),
        'aspect': 'equal'})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #36
0
def CIE_1976_UCS_chromaticity_diagram_plot(
        cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots the *CIE 1976 UCS Chromaticity Diagram*.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1976_UCS_chromaticity_diagram_plot()  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    image = matplotlib.image.imread(
        os.path.join(PLOTTING_RESOURCES_DIRECTORY,
                     'CIE_1976_UCS_Chromaticity_Diagram_{0}_Large.png'.format(
                         cmfs.name.replace(' ', '_'))))
    pylab.imshow(image, interpolation='nearest', extent=(0, 1, 0, 1))

    labels = [420, 430, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530,
              540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 640, 680]

    wavelengths = cmfs.wavelengths
    equal_energy = np.array([1 / 3] * 2)

    illuminant = ILLUMINANTS.get(
        'CIE 1931 2 Degree Standard Observer').get('D50')

    uv = np.array([Luv_to_uv(XYZ_to_Luv(XYZ, illuminant))
                   for XYZ in cmfs.values])

    wavelengths_chromaticity_coordinates = dict(zip(wavelengths, uv))

    pylab.plot(uv[:, 0], uv[:, 1], color='black', linewidth=2)
    pylab.plot((uv[-1][0], uv[0][0]),
               (uv[-1][1], uv[0][1]),
               color='black',
               linewidth=2)

    for label in labels:
        u, v = wavelengths_chromaticity_coordinates.get(label)
        pylab.plot(u, v, 'o', color='black', linewidth=2)

        index = bisect.bisect(wavelengths, label)
        left = wavelengths[index - 1] if index >= 0 else wavelengths[index]
        right = (wavelengths[index]
                 if index < len(wavelengths) else
                 wavelengths[-1])

        dx = (wavelengths_chromaticity_coordinates.get(right)[0] -
              wavelengths_chromaticity_coordinates.get(left)[0])
        dy = (wavelengths_chromaticity_coordinates.get(right)[1] -
              wavelengths_chromaticity_coordinates.get(left)[1])

        norme = lambda x: x / np.linalg.norm(x)

        uv = np.array([u, v])
        direction = np.array((-dy, dx))

        normal = (np.array((-dy, dx))
                  if np.dot(norme(uv - equal_energy),
                            norme(direction)) > 0 else
                  np.array((dy, -dx)))
        normal = norme(normal)
        normal /= 25

        pylab.plot([u, u + normal[0] * 0.75],
                   [v, v + normal[1] * 0.75],
                   color='black',
                   linewidth=1.5)
        pylab.text(u + normal[0],
                   v + normal[1],
                   label,
                   clip_on=True,
                   ha='left' if normal[0] >= 0 else 'right',
                   va='center',
                   fontdict={'size': 'small'})

    settings.update({
        'title': 'CIE 1976 UCS Chromaticity Diagram - {0}'.format(cmfs.title),
        'x_label': 'CIE u\'',
        'y_label': 'CIE v\'',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'bounding_box': [-0.1, .7, -.1, .7],
        'bbox_inches': 'tight',
        'pad_inches': 0})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #37
0
def corresponding_chromaticities_prediction_plot(experiment=1,
                                                 model='Von Kries',
                                                 transform='CAT02',
                                                 **kwargs):
    """
    Plots given chromatic adaptation model corresponding chromaticities
    prediction.

    Parameters
    ----------
    experiment : int, optional
        Corresponding chromaticities prediction experiment number.
    model : unicode, optional
        Corresponding chromaticities prediction model name.
    transform : unicode, optional
        Transformation to use with *Von Kries* chromatic adaptation model.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.
    show_diagram_colours : bool, optional
        {:func:`CIE_1976_UCS_chromaticity_diagram_plot`}
        Whether to display the chromaticity diagram background colours.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> corresponding_chromaticities_prediction_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    settings.update({
        'title': (('Corresponding Chromaticities Prediction\n{0} ({1}) - '
                   'Experiment {2}\nCIE 1976 UCS Chromaticity Diagram').format(
                       model, transform, experiment)
                  if model.lower() in ('von kries', 'vonkries') else
                  ('Corresponding Chromaticities Prediction\n{0} - '
                   'Experiment {1}\nCIE 1976 UCS Chromaticity Diagram').format(
                       model, experiment)),
        'standalone':
        False
    })
    settings.update(kwargs)

    CIE_1976_UCS_chromaticity_diagram_plot(**settings)

    results = corresponding_chromaticities_prediction(experiment,
                                                      transform=transform)

    for result in results:
        name, uvp_t, uvp_m, uvp_p = result
        pylab.arrow(uvp_t[0],
                    uvp_t[1],
                    uvp_p[0] - uvp_t[0] - 0.1 * (uvp_p[0] - uvp_t[0]),
                    uvp_p[1] - uvp_t[1] - 0.1 * (uvp_p[1] - uvp_t[1]),
                    head_width=0.005,
                    head_length=0.005,
                    linewidth=0.5,
                    color='black')
        pylab.plot(uvp_t[0], uvp_t[1], 'o', color='white')
        pylab.plot(uvp_m[0], uvp_m[1], '^', color='white')
        pylab.plot(uvp_p[0], uvp_p[1], '^', color='black')
    settings.update({
        'x_tighten': True,
        'y_tighten': True,
        'limits': (-0.1, 0.7, -0.1, 0.7),
        'standalone': True
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #38
0
def CIE_1931_chromaticity_diagram_colours_plot(
        surface=1.25,
        spacing=0.00075,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram* colours.

    Parameters
    ----------
    surface : numeric, optional
        Generated markers surface.
    spacing : numeric, optional
        Spacing between markers.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_colours_plot()  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (32, 32)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = ILLUMINANTS.get(
        'CIE 1931 2 Degree Standard Observer').get('E')

    XYZs = [value for key, value in cmfs]

    path = matplotlib.path.Path([XYZ_to_xy(x) for x in XYZs])
    x_dot, y_dot, colours = [], [], []
    for i in np.arange(0, 1, spacing):
        for j in np.arange(0, 1, spacing):
            if path.contains_path(matplotlib.path.Path([[i, j], [i, j]])):
                x_dot.append(i)
                y_dot.append(j)

                XYZ = xy_to_XYZ((i, j))
                RGB = normalise(XYZ_to_sRGB(XYZ, illuminant))

                colours.append(RGB)

    pylab.scatter(x_dot, y_dot, color=colours, s=surface)

    settings.update({
        'no_ticks': True,
        'bounding_box': [0, 1, 0, 1],
        'bbox_inches': 'tight',
        'pad_inches': 0})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #39
0
def multi_cmfs_plot(cmfs=None, **kwargs):
    """
    Plots given colour matching functions.

    Parameters
    ----------
    cmfs : array_like, optional
        Colour matching functions to plot.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> cmfs = [
    ... 'CIE 1931 2 Degree Standard Observer',
    ... 'CIE 1964 10 Degree Standard Observer']
    >>> multi_cmfs_plot(cmfs)  # doctest: +SKIP
    """

    canvas(**kwargs)

    if cmfs is None:
        cmfs = ('CIE 1931 2 Degree Standard Observer',
                'CIE 1964 10 Degree Standard Observer')

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for axis, rgb in (('x', (1, 0, 0)), ('y', (0, 1, 0)), ('z', (0, 0, 1))):
        for i, cmfs_i in enumerate(cmfs):
            cmfs_i = get_cmfs(cmfs_i)

            rgb = [
                reduce(lambda y, _: y * 0.5, range(i), x)  # noqa
                for x in rgb
            ]
            wavelengths, values = tuple(
                zip(*[(key, value) for key, value in getattr(cmfs_i, axis)]))

            shape = cmfs_i.shape
            x_limit_min.append(shape.start)
            x_limit_max.append(shape.end)
            y_limit_min.append(min(values))
            y_limit_max.append(max(values))

            pylab.plot(wavelengths,
                       values,
                       color=rgb,
                       label=u'{0} - {1}'.format(cmfs_i.labels.get(axis),
                                                 cmfs_i.title),
                       linewidth=2)

    settings = {
        'title':
        '{0} - Colour Matching Functions'.format(', '.join(
            [get_cmfs(c).title for c in cmfs])),
        'x_label':
        'Wavelength $\\lambda$ (nm)',
        'y_label':
        'Tristimulus Values',
        'x_tighten':
        True,
        'legend':
        True,
        'legend_location':
        'upper right',
        'grid':
        True,
        'y_axis_line':
        True,
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max))
    }
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #40
0
def RGB_colourspaces_CIE_1931_chromaticity_diagram_plot(
        colourspaces=None,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots given *RGB* colourspaces in *CIE 1931 Chromaticity Diagram*.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_CIE_1931_chromaticity_diagram_plot(
    ...     c)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut')

    cmfs, name = get_cmfs(cmfs), cmfs

    settings = {
        'title': '{0} - {1} - CIE 1931 Chromaticity Diagram'.format(
            ', '.join(colourspaces), name),
        'standalone': False}
    settings.update(kwargs)

    CIE_1931_chromaticity_diagram_plot(**settings)

    x_limit_min, x_limit_max = [-0.1], [0.9]
    y_limit_min, y_limit_max = [-0.1], [0.9]

    settings = {'colour_cycle_map': 'rainbow',
                'colour_cycle_count': len(colourspaces)}
    settings.update(kwargs)

    cycle = colour_cycle(**settings)

    for colourspace in colourspaces:
        if colourspace == 'Pointer Gamut':
            xy = np.asarray(POINTER_GAMUT_BOUNDARIES)
            alpha_p, colour_p = 0.85, '0.95'
            pylab.plot(xy[..., 0],
                       xy[..., 1],
                       label='Pointer\'s Gamut',
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)
            pylab.plot((xy[-1][0], xy[0][0]),
                       (xy[-1][1], xy[0][1]),
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)

            XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                             POINTER_GAMUT_ILLUMINANT)
            xy = XYZ_to_xy(XYZ, POINTER_GAMUT_ILLUMINANT)
            pylab.scatter(xy[..., 0],
                          xy[..., 1],
                          alpha=alpha_p / 2,
                          color=colour_p,
                          marker='+')

        else:
            colourspace, name = get_RGB_colourspace(colourspace), colourspace

            r, g, b, _a = next(cycle)

            primaries = colourspace.primaries
            whitepoint = colourspace.whitepoint

            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       color=(r, g, b),
                       label=colourspace.name,
                       linewidth=2)
            pylab.plot((whitepoint[0], whitepoint[0]),
                       (whitepoint[1], whitepoint[1]),
                       'o',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[0, 0], primaries[1, 0]),
                       (primaries[0, 1], primaries[1, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[1, 0], primaries[2, 0]),
                       (primaries[1, 1], primaries[2, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((primaries[2, 0], primaries[0, 0]),
                       (primaries[2, 1], primaries[0, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)

            x_limit_min.append(np.amin(primaries[..., 0]) - 0.1)
            y_limit_min.append(np.amin(primaries[..., 1]) - 0.1)
            x_limit_max.append(np.amax(primaries[..., 0]) + 0.1)
            y_limit_max.append(np.amax(primaries[..., 1]) + 0.1)

    settings.update({
        'legend': True,
        'legend_location': 'upper right',
        'x_tighten': True,
        'y_tighten': True,
        'limits': (min(x_limit_min), max(x_limit_max),
                   min(y_limit_min), max(y_limit_max)),
        'standalone': True})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #41
0
def blackbody_spectral_radiance_plot(
        temperature=3500,
        cmfs='CIE 1931 2 Degree Standard Observer',
        blackbody='VY Canis Major',
        **kwargs):
    """
    Plots given blackbody spectral radiance.

    Parameters
    ----------
    temperature : numeric, optional
        Blackbody temperature.
    cmfs : unicode, optional
        Standard observer colour matching functions.
    blackbody : unicode, optional
        Blackbody name.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> blackbody_spectral_radiance_plot()  # doctest: +SKIP
    """

    canvas(**kwargs)

    cmfs = get_cmfs(cmfs)

    matplotlib.pyplot.subplots_adjust(hspace=0.4)

    spd = blackbody_spd(temperature, cmfs.shape)

    matplotlib.pyplot.figure(1)
    matplotlib.pyplot.subplot(211)

    settings = {
        'title': '{0} - Spectral Radiance'.format(blackbody),
        'y_label': 'W / (sr m$^2$) / m',
        'standalone': False
    }
    settings.update(kwargs)

    single_spd_plot(spd, cmfs.name, **settings)

    XYZ = spectral_to_XYZ(spd, cmfs)
    RGB = normalise_maximum(XYZ_to_sRGB(XYZ / 100))

    matplotlib.pyplot.subplot(212)

    settings = {
        'title': '{0} - Colour'.format(blackbody),
        'x_label': '{0}K'.format(temperature),
        'y_label': '',
        'aspect': None,
        'standalone': False
    }

    single_colour_plot(ColourParameter(name='', RGB=RGB), **settings)

    settings = {'standalone': True}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)
    return display(**settings)
Example #42
0
def multi_cctf_plot(colourspaces=None, decoding_cctf=False, **kwargs):
    """
    Plots given colourspaces colour component transfer functions.

    Parameters
    ----------
    colourspaces : array_like, optional
        Colourspaces colour component transfer function to plot.
    decoding_cctf : bool
        Plot decoding colour component transfer function instead.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> multi_cctf_plot(['Rec. 709', 'sRGB'])  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'sRGB')

    samples = np.linspace(0, 1, 1000)
    for colourspace in colourspaces:
        colourspace = get_RGB_colourspace(colourspace)

        RGBs = (colourspace.decoding_cctf(samples)
                if decoding_cctf else colourspace.encoding_cctf(samples))

        pylab.plot(samples,
                   RGBs,
                   label=u'{0}'.format(colourspace.name),
                   linewidth=2)

    settings.update({
        'title': '{0} - {1} CCTFs'.format(
            ', '.join(colourspaces),
            'Decoding' if decoding_cctf else 'Encoding'),
        'x_tighten': True,
        'x_label': 'Signal Value' if decoding_cctf else 'Tristimulus Value',
        'y_label': 'Tristimulus Value' if decoding_cctf else 'Signal Value',
        'legend': True,
        'legend_location': 'upper left',
        'grid': True,
        'limits': (0, 1, 0, 1),
        'aspect': 'equal'})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #43
0
def the_blue_sky_plot(
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the blue sky.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> the_blue_sky_plot()  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    cmfs, name = get_cmfs(cmfs), cmfs

    ASTM_G_173_spd = ASTM_G_173_ETR.clone()
    rayleigh_spd = rayleigh_scattering_spd()
    ASTM_G_173_spd.align(rayleigh_spd.shape)

    spd = rayleigh_spd * ASTM_G_173_spd

    matplotlib.pyplot.subplots_adjust(hspace=0.4)

    matplotlib.pyplot.figure(1)
    matplotlib.pyplot.subplot(211)

    settings = {
        'title': 'The Blue Sky - Synthetic Spectral Power Distribution',
        'y_label': u'W / m-2 / nm-1',
        'standalone': False}
    settings.update(kwargs)

    single_spd_plot(spd, name, **settings)

    matplotlib.pyplot.subplot(212)

    settings = {
        'title': 'The Blue Sky - Colour',
        'x_label': ('The sky is blue because molecules in the atmosphere '
                    'scatter shorter wavelengths more than longer ones.\n'
                    'The synthetic spectral power distribution is computed as '
                    'follows: '
                    '(ASTM G-173 ETR * Standard Air Rayleigh Scattering).'),
        'y_label': '',
        'aspect': None,
        'standalone': False}

    blue_sky_color = XYZ_to_sRGB(spectral_to_XYZ(spd))
    single_colour_plot(colour_parameter('', normalise(blue_sky_color)),
                       **settings)

    settings = {'standalone': True}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)
    return display(**settings)
Example #44
0
def RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot(
        colourspaces=None,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots given *RGB* colourspaces in *CIE 1976 UCS Chromaticity Diagram*.

    Parameters
    ----------
    colourspaces : array_like, optional
        *RGB* colourspaces to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.
    show_diagram_colours : bool, optional
        {:func:`CIE_1976_UCS_chromaticity_diagram_plot`},
        Whether to display the chromaticity diagram background colours.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> c = ['Rec. 709', 'ACEScg', 'S-Gamut']
    >>> RGB_colourspaces_CIE_1976_UCS_chromaticity_diagram_plot(
    ...     c)  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    if colourspaces is None:
        colourspaces = ('Rec. 709', 'ACEScg', 'S-Gamut', 'Pointer Gamut')

    cmfs, name = get_cmfs(cmfs), cmfs

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    settings = {
        'title':
        '{0} - {1} - CIE 1976 UCS Chromaticity Diagram'.format(
            ', '.join(colourspaces), name),
        'standalone':
        False
    }
    settings.update(kwargs)

    CIE_1976_UCS_chromaticity_diagram_plot(**settings)

    x_limit_min, x_limit_max = [-0.1], [0.7]
    y_limit_min, y_limit_max = [-0.1], [0.7]

    settings = {
        'colour_cycle_map': 'rainbow',
        'colour_cycle_count': len(colourspaces)
    }
    settings.update(kwargs)

    cycle = colour_cycle(**settings)

    for colourspace in colourspaces:
        if colourspace == 'Pointer Gamut':
            uv = Luv_to_uv(
                XYZ_to_Luv(xy_to_XYZ(POINTER_GAMUT_BOUNDARIES), illuminant),
                illuminant)
            alpha_p, colour_p = 0.85, '0.95'
            pylab.plot(uv[..., 0],
                       uv[..., 1],
                       label='Pointer\'s Gamut',
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)
            pylab.plot((uv[-1][0], uv[0][0]), (uv[-1][1], uv[0][1]),
                       color=colour_p,
                       alpha=alpha_p,
                       linewidth=2)

            XYZ = Lab_to_XYZ(LCHab_to_Lab(POINTER_GAMUT_DATA),
                             POINTER_GAMUT_ILLUMINANT)
            uv = Luv_to_uv(XYZ_to_Luv(XYZ, illuminant), illuminant)
            pylab.scatter(uv[..., 0],
                          uv[..., 1],
                          alpha=alpha_p / 2,
                          color=colour_p,
                          marker='+')

        else:
            colourspace, name = get_RGB_colourspace(colourspace), colourspace

            r, g, b, _a = next(cycle)

            # RGB colourspaces such as *ACES2065-1* have primaries with
            # chromaticity coordinates set to 0 thus we prevent nan from being
            # yield by zero division in later colour transformations.
            P = np.where(colourspace.primaries == 0, EPSILON,
                         colourspace.primaries)

            P = Luv_to_uv(XYZ_to_Luv(xy_to_XYZ(P), illuminant), illuminant)
            W = Luv_to_uv(
                XYZ_to_Luv(xy_to_XYZ(colourspace.whitepoint), illuminant),
                illuminant)

            pylab.plot((W[0], W[0]), (W[1], W[1]),
                       color=(r, g, b),
                       label=colourspace.name,
                       linewidth=2)
            pylab.plot((W[0], W[0]), (W[1], W[1]),
                       'o',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((P[0, 0], P[1, 0]), (P[0, 1], P[1, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((P[1, 0], P[2, 0]), (P[1, 1], P[2, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)
            pylab.plot((P[2, 0], P[0, 0]), (P[2, 1], P[0, 1]),
                       'o-',
                       color=(r, g, b),
                       linewidth=2)

            x_limit_min.append(np.amin(P[..., 0]) - 0.1)
            y_limit_min.append(np.amin(P[..., 1]) - 0.1)
            x_limit_max.append(np.amax(P[..., 0]) + 0.1)
            y_limit_max.append(np.amax(P[..., 1]) + 0.1)

    settings.update({
        'legend':
        True,
        'legend_location':
        'upper right',
        'x_tighten':
        True,
        'y_tighten':
        True,
        'limits': (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                   max(y_limit_max)),
        'standalone':
        True
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #45
0
def colour_quality_bars_plot(specifications,
                             labels=True,
                             hatching=None,
                             hatching_repeat=1,
                             **kwargs):
    """
    Plots the colour quality data of given illuminants or light sources colour
    quality specifications.

    Parameters
    ----------
    specifications : array_like
        Array of illuminants or light sources colour quality specifications.
    labels : bool, optional
        Add labels above bars.
    hatching : bool or None, optional
        Use hatching for the bars.
    hatching_repeat : int, optional
        Hatching pattern repeat.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> from colour import (
    ...     ILLUMINANTS_RELATIVE_SPDS,
    ...     LIGHT_SOURCES_RELATIVE_SPDS,
    ...     SpectralShape)
    >>> illuminant = ILLUMINANTS_RELATIVE_SPDS['F2']
    >>> light_source = LIGHT_SOURCES_RELATIVE_SPDS['Kinoton 75P']
    >>> light_source = light_source.clone().align(SpectralShape(360, 830, 1))
    >>> cqs_i = colour_quality_scale(illuminant, additional_data=True)
    >>> cqs_l = colour_quality_scale(light_source, additional_data=True)
    >>> colour_quality_bars_plot([cqs_i, cqs_l])  # doctest: +SKIP
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    bar_width = 0.5
    y_ticks_interval = 10
    count_s, count_Q_as = len(specifications), 0
    patterns = cycle(DEFAULT_HATCH_PATTERNS)
    if hatching is None:
        hatching = False if count_s == 1 else True
    for i, specification in enumerate(specifications):
        Q_a, Q_as, colorimetry_data = (specification.Q_a, specification.Q_as,
                                       specification.colorimetry_data)

        count_Q_as = len(Q_as)
        colours = (
            [[1] * 3] +
            [np.clip(XYZ_to_sRGB(x.XYZ), 0, 1) for x in colorimetry_data[0]])

        x = (i + np.arange(0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
                           dtype=np.float_)) * bar_width
        y = [s[1].Q_a for s in sorted(Q_as.items(), key=lambda s: s[0])]
        y = np.array([Q_a] + list(y))

        if np.sign(np.min(y)) < 0:
            warning(
                ('"{0}" spectral distribution has negative "Q_a" value(s), '
                 'using absolute value(s) '
                 'for plotting purpose!'.format(specification.name)))

            y = np.abs(y)

        bars = pylab.bar(x,
                         y,
                         color=colours,
                         width=bar_width,
                         hatch=(next(patterns) *
                                hatching_repeat if hatching else None),
                         label=specification.name)

        if labels:
            label_rectangles(
                bars,
                rotation='horizontal' if count_s == 1 else 'vertical',
                offset=(0 if count_s == 1 else 3 / 100 * count_s + 65 / 1000,
                        0.025),
                text_size=-5 / 7 * count_s + 12.5)

    pylab.axhline(y=100, color='black', linestyle='--')

    pylab.xticks(
        (np.arange(0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
                   dtype=np.float_) * bar_width + (count_s * bar_width / 2)),
        ['Qa'] +
        ['Q{0}'.format(index + 1) for index in range(0, count_Q_as + 1, 1)])
    pylab.yticks(range(0, 100 + y_ticks_interval, y_ticks_interval))

    settings.update({
        'title':
        'Colour Quality',
        'legend':
        hatching,
        'x_tighten':
        True,
        'y_tighten':
        True,
        'limits': (-bar_width, ((count_Q_as + 1) * (count_s + 1)) / 2, 0, 120),
        'aspect':
        1 / (120 / (bar_width + len(Q_as) + bar_width * 2))
    })
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #46
0
def tonemapping_operator_image_plot(image,
                                    luminance_function,
                                    log_scale=False,
                                    OECF=DEFAULT_PLOTTING_OECF,
                                    **kwargs):
    """
    Plots given tonemapped image with superimposed luminance mapping function.

    Parameters
    ----------
    image : array_like
         Tonemapped image to plot.
    luminance_function : callable
        Luminance mapping function.
    log_scale : bool, optional
        Use a log scale for plotting the luminance mapping function.
    OECF : callable, optional
        OECF / opto-electronic conversion function used for plotting.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.
    """
    shape = image.shape
    limits = [0, 1, 0, 1]

    image = np.clip(OECF(image), 0, 1)
    pylab.imshow(image,
                 aspect=shape[0] / shape[1],
                 extent=limits,
                 interpolation='nearest')

    pylab.plot(np.linspace(0, 1, len(luminance_function)),
               luminance_function,
               color='red')

    settings = {
        'figure_size': (8, 8),
        'x_label': 'Input Luminance',
        'y_label': 'Output Luminance',
        'x_ticker': True,
        'y_ticker': True,
        'grid': True,
        'x_tighten': True,
        'y_tighten': True,
        'limits': limits}
    settings.update(kwargs)

    if log_scale:
        settings.update({
            'x_label': '$log_2$ Input Luminance',
            'x_ticker_locator': matplotlib.ticker.AutoMinorLocator(0.5)})
        matplotlib.pyplot.gca().set_xscale('log', basex=2)
        matplotlib.pyplot.gca().xaxis.set_major_formatter(
            matplotlib.ticker.ScalarFormatter())

    canvas(**settings)
    decorate(**settings)
    boundaries(**settings)
    return display(**settings)
Example #47
0
def the_blue_sky_plot(cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots the blue sky.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> the_blue_sky_plot()  # doctest: +SKIP
    True
    """

    canvas(**kwargs)

    cmfs, name = get_cmfs(cmfs), cmfs

    ASTM_G_173_spd = ASTM_G_173_ETR.clone()
    rayleigh_spd = rayleigh_scattering_spd()
    ASTM_G_173_spd.align(rayleigh_spd.shape)

    spd = rayleigh_spd * ASTM_G_173_spd

    matplotlib.pyplot.subplots_adjust(hspace=0.4)

    matplotlib.pyplot.figure(1)
    matplotlib.pyplot.subplot(211)

    settings = {
        'title': 'The Blue Sky - Synthetic Spectral Power Distribution',
        'y_label': u'W / m-2 / nm-1',
        'standalone': False
    }
    settings.update(kwargs)

    single_spd_plot(spd, name, **settings)

    matplotlib.pyplot.subplot(212)

    settings = {
        'title':
        'The Blue Sky - Colour',
        'x_label': ('The sky is blue because molecules in the atmosphere '
                    'scatter shorter wavelengths more than longer ones.\n'
                    'The synthetic spectral power distribution is computed as '
                    'follows: '
                    '(ASTM G-173 ETR * Standard Air Rayleigh Scattering).'),
        'y_label':
        '',
        'aspect':
        None,
        'standalone':
        False
    }

    blue_sky_color = XYZ_to_sRGB(spectral_to_XYZ(spd))
    single_colour_plot(ColourParameter('', normalise(blue_sky_color)),
                       **settings)

    settings = {'standalone': True}
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #48
0
def colour_quality_bars_plot(specifications,
                             labels=True,
                             hatching=None,
                             hatching_repeat=1,
                             **kwargs):
    """
    Plots the colour quality data of given illuminants or light sources colour
    quality specifications.

    Parameters
    ----------
    specifications : array_like
        Array of illuminants or light sources colour quality specifications.
    labels : bool, optional
        Add labels above bars.
    hatching : bool or None, optional
        Use hatching for the bars.
    hatching_repeat : int, optional
        Hatching pattern repeat.
    \**kwargs : dict, optional
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> from colour import (
    ...     ILLUMINANTS_RELATIVE_SPDS,
    ...     LIGHT_SOURCES_RELATIVE_SPDS)
    >>> illuminant = ILLUMINANTS_RELATIVE_SPDS.get('F2')
    >>> light_source = LIGHT_SOURCES_RELATIVE_SPDS.get('Kinoton 75P')
    >>> cqs_i = colour_quality_scale(illuminant, additional_data=True)
    >>> cqs_l = colour_quality_scale(light_source, additional_data=True)
    >>> colour_quality_bars_plot([cqs_i, cqs_l])  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    bar_width = 0.5
    y_ticks_steps = 10
    count_s, count_Q_as = len(specifications), 0
    patterns = cycle(DEFAULT_HATCH_PATTERNS)
    if hatching is None:
        hatching = False if count_s == 1 else True
    for i, specification in enumerate(specifications):
        Q_a, Q_as, colorimetry_data = (specification.Q_a,
                                       specification.Q_as,
                                       specification.colorimetry_data)

        count_Q_as = len(Q_as)
        colours = ([[1] * 3] + [np.clip(XYZ_to_sRGB(x.XYZ), 0, 1)
                                for x in colorimetry_data[0]])

        x = (i + np.arange(0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
                           dtype=np.float)) * bar_width
        y = [s[1].Q_a for s in sorted(Q_as.items(), key=lambda s: s[0])]
        y = np.array([Q_a] + list(y))

        if np.sign(np.min(y)) < 0:
            warning(
                ('"{0}" spectral distribution has negative "Q_a" value(s), '
                 'using absolute value(s) '
                 'for plotting purpose!'.format(specification.name)))

            y = np.abs(y)

        bars = pylab.bar(x,
                         y,
                         color=colours,
                         width=bar_width,
                         hatch=(next(patterns) * hatching_repeat
                                if hatching else None),
                         label=specification.name)

        if labels:
            label_rectangles(
                bars,
                rotation='horizontal' if count_s == 1 else 'vertical',
                offset=(0 if count_s == 1 else 3 / 100 * count_s + 65 / 1000,
                        0.025),
                text_size=-5 / 7 * count_s + 12.5)

    pylab.axhline(y=100, color='black', linestyle='--')

    pylab.xticks((np.arange(0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
                            dtype=np.float) *
                  bar_width + (count_s * bar_width / 2)),
                 ['Qa'] + ['Q{0}'.format(index + 1)
                           for index in range(0, count_Q_as + 1, 1)])
    pylab.yticks(range(0, 100 + y_ticks_steps, y_ticks_steps))

    settings.update({
        'title': 'Colour Quality',
        'legend': hatching,
        'x_tighten': True,
        'y_tighten': True,
        'limits': (-bar_width,
                   ((count_Q_as + 1) * (count_s + 1)) / 2,
                   0,
                   120),
        'aspect': 1 / (120 / (bar_width + len(Q_as) + bar_width * 2))})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #49
0
def CIE_1931_chromaticity_diagram_colours_plot(
        surface=1,
        samples=4096,
        cmfs='CIE 1931 2 Degree Standard Observer',
        **kwargs):
    """
    Plots the *CIE 1931 Chromaticity Diagram* colours.

    Parameters
    ----------
    surface : numeric, optional
        Generated markers surface.
    samples : numeric, optional
        Samples count on one axis.
    cmfs : unicode, optional
        Standard observer colour matching functions used for diagram bounds.

    Other Parameters
    ----------------
    \**kwargs : dict, optional
        {:func:`boundaries`, :func:`canvas`, :func:`decorate`,
        :func:`display`},
        Please refer to the documentation of the previously listed definitions.

    Returns
    -------
    Figure
        Current figure or None.

    Examples
    --------
    >>> CIE_1931_chromaticity_diagram_colours_plot()  # doctest: +SKIP
    """

    settings = {'figure_size': (64, 64)}
    settings.update(kwargs)

    canvas(**settings)

    cmfs = get_cmfs(cmfs)

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    triangulation = Delaunay(XYZ_to_xy(cmfs.values, illuminant),
                             qhull_options='QJ')
    xx, yy = np.meshgrid(np.linspace(0, 1, samples),
                         np.linspace(0, 1, samples))
    xy = tstack((xx, yy))
    xy = xy[triangulation.find_simplex(xy) > 0]

    XYZ = xy_to_XYZ(xy)

    RGB = normalise_maximum(XYZ_to_sRGB(XYZ, illuminant), axis=-1)

    x_dot, y_dot = tsplit(xy)

    pylab.scatter(x_dot, y_dot, color=RGB, s=surface)

    settings.update({
        'x_ticker': False,
        'y_ticker': False,
        'bounding_box': (0, 1, 0, 1)
    })
    settings.update(kwargs)

    ax = matplotlib.pyplot.gca()
    matplotlib.pyplot.setp(ax, frame_on=False)

    boundaries(**settings)
    decorate(**settings)

    return display(**settings)
Example #50
0
def colour_quality_bars_plot(specification, **kwargs):
    """
    Plots the colour quality data of given illuminant or light source colour
    quality specification.

    Parameters
    ----------
    specification : CRI_Specification or VS_ColourQualityScaleData
        Illuminant or light source specification colour quality specification.
    \*\*kwargs : \*\*
        Keywords arguments.

    Returns
    -------
    bool
        Definition success.

    Examples
    --------
    >>> from colour import ILLUMINANTS_RELATIVE_SPDS
    >>> illuminant = ILLUMINANTS_RELATIVE_SPDS.get('F2')
    >>> colour_quality_bars_plot(illuminant)  # doctest: +SKIP
    True
    """

    settings = {'figure_size': (DEFAULT_FIGURE_WIDTH, DEFAULT_FIGURE_WIDTH)}
    settings.update(kwargs)

    canvas(**settings)

    axis = matplotlib.pyplot.gca()

    Q_a, Q_as, colorimetry_data = (specification.Q_a,
                                   specification.Q_as,
                                   specification.colorimetry_data)

    colours = ([[1] * 3] + [normalise(XYZ_to_sRGB(x.XYZ / 100))
                            for x in colorimetry_data[0]])
    x, y = tuple(zip(*[(x[0], x[1].Q_a) for x in sorted(Q_as.items(),
                                                        key=lambda x: x[0])]))
    x, y = np.array([0] + list(x)), np.array([Q_a] + list(y))

    positive = True if np.sign(min(y)) in (0, 1) else False

    width = 0.5
    bars = pylab.bar(x, y, color=colours, width=width)
    y_ticks_steps = 10
    pylab.yticks(range(0 if positive else -100,
                       100 + y_ticks_steps,
                       y_ticks_steps))
    pylab.xticks(x + width / 2,
                 ['Qa'] + ['Q{0}'.format(index) for index in x[1:]])

    def label_bars(bars):
        """
        Add labels above given bars.
        """
        for bar in bars:
            y = bar.get_y()
            height = bar.get_height()
            value = height if np.sign(y) in (0, 1) else -height
            axis.text(bar.get_x() + bar.get_width() / 2,
                      0.025 * height + height + y,
                      '{0:.1f}'.format(value),
                      ha='center', va='bottom')

    label_bars(bars)

    settings.update({
        'title': 'Colour Quality',
        'grid': True,
        'grid_axis': 'y',
        'x_tighten': True,
        'y_tighten': True,
        'limits': [-width,
                   len(Q_as) + width * 2,
                   0 if positive else -110,
                   110],
        'aspect': 1 / ((110 if positive else 220) /
                       (width + len(Q_as) + width * 2))})
    settings.update(kwargs)

    boundaries(**settings)
    decorate(**settings)
    return display(**settings)