Example #1
0
    def test_wavelength_to_XYZ(self):
        """
        Tests
        :func:`colour.colorimetry.tristimulus.wavelength_to_XYZ` definition.
        """

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480,
                CMFS.get('CIE 1931 2 Degree Standard Observer')),
            np.array([0.09564, 0.13902, 0.81295]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480,
                CMFS.get('CIE 2012 2 Degree Standard Observer')),
            np.array([0.08182895, 0.1788048, 0.7552379]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                641.5,
                CMFS.get('CIE 2012 2 Degree Standard Observer')),
            np.array([0.44575583, 0.18184213, 0.]),
            decimal=7)
Example #2
0
    def test_wavelength_to_XYZ(self):
        """
        Test :func:`colour.colorimetry.tristimulus_values.wavelength_to_XYZ`
        definition.
        """

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480, MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]),
            np.array([0.09564, 0.13902, 0.81295]),
            decimal=7,
        )

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480, MSDS_CMFS["CIE 2012 2 Degree Standard Observer"]),
            np.array([0.08182895, 0.17880480, 0.75523790]),
            decimal=7,
        )

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                641.5, MSDS_CMFS["CIE 2012 2 Degree Standard Observer"]),
            np.array([0.44575583, 0.18184213, 0.00000000]),
            decimal=7,
        )
Example #3
0
    def test_n_dimensional_wavelength_to_XYZ(self):
        """
        Tests :func:`colour.colorimetry.tristimulus.wavelength_to_XYZ`
        definition n-dimensional arrays support.
        """

        cmfs = CMFS.get('CIE 1931 2 Degree Standard Observer')
        wl = 480
        XYZ = np.array([0.09564, 0.13902, 0.81295])
        np.testing.assert_almost_equal(
            wavelength_to_XYZ(wl, cmfs),
            XYZ,
            decimal=7)

        wl = np.tile(wl, 6)
        XYZ = np.tile(XYZ, (6, 1))
        np.testing.assert_almost_equal(
            wavelength_to_XYZ(wl, cmfs),
            XYZ,
            decimal=7)

        wl = np.reshape(wl, (2, 3))
        XYZ = np.reshape(XYZ, (2, 3, 3))
        np.testing.assert_almost_equal(
            wavelength_to_XYZ(wl, cmfs),
            XYZ,
            decimal=7)

        wl = np.reshape(wl, (2, 3, 1))
        XYZ = np.reshape(XYZ, (2, 3, 1, 3))
        np.testing.assert_almost_equal(
            wavelength_to_XYZ(wl, cmfs),
            XYZ,
            decimal=7)
Example #4
0
    def test_n_dimensional_wavelength_to_XYZ(self):
        """
        Tests :func:`colour.colorimetry.tristimulus.wavelength_to_XYZ`
        definition n-dimensional arrays support.
        """

        cmfs = CMFS['CIE 1931 2 Degree Standard Observer']
        wl = 480
        XYZ = np.array([0.09564, 0.13902, 0.81295])
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)

        wl = np.tile(wl, 6)
        XYZ = np.tile(XYZ, (6, 1))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)

        wl = np.reshape(wl, (2, 3))
        XYZ = np.reshape(XYZ, (2, 3, 3))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)

        wl = np.reshape(wl, (2, 3, 1))
        XYZ = np.reshape(XYZ, (2, 3, 1, 3))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)
Example #5
0
    def test_n_dimensional_wavelength_to_XYZ(self):
        """
        Test :func:`colour.colorimetry.tristimulus_values.wavelength_to_XYZ`
        definition n-dimensional arrays support.
        """

        cmfs = MSDS_CMFS["CIE 1931 2 Degree Standard Observer"]
        wl = 480
        XYZ = wavelength_to_XYZ(wl, cmfs)

        wl = np.tile(wl, 6)
        XYZ = np.tile(XYZ, (6, 1))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)

        wl = np.reshape(wl, (2, 3))
        XYZ = np.reshape(XYZ, (2, 3, 3))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)

        wl = np.reshape(wl, (2, 3, 1))
        XYZ = np.reshape(XYZ, (2, 3, 1, 3))
        np.testing.assert_almost_equal(wavelength_to_XYZ(wl, cmfs),
                                       XYZ,
                                       decimal=7)
Example #6
0
def single_spd_plot(spd, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots given spectral power distribution.

    Parameters
    ----------
    spd : SpectralPowerDistribution, optional
        Spectral power distribution to plot.
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.
    \*\*kwargs : \*\*
        Keywords arguments.

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

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> spd = SpectralPowerDistribution('Custom', data)
    >>> single_spd_plot(spd)  # doctest: +SKIP
    True
    """

    cmfs, name = get_cmfs(cmfs), cmfs

    shape = cmfs.shape
    spd = spd.clone().interpolate(shape)
    wavelengths = shape.range()

    colours = []
    y1 = []

    for wavelength, value in spd:
        XYZ = wavelength_to_XYZ(wavelength, cmfs)
        colours.append(XYZ_to_sRGB(XYZ))
        y1.append(value)

    colours = normalise(colours)

    settings = {
        'title': '"{0}" - {1}'.format(spd.name, cmfs.name),
        'x_label': u'Wavelength λ (nm)',
        'y_label': 'Spectral Power Distribution',
        'x_tighten': True,
        'x_ticker': True,
        'y_ticker': True
    }

    settings.update(kwargs)
    return colour_parameters_plot([
        colour_parameter(x=x[0], y1=x[1], RGB=x[2])
        for x in tuple(zip(wavelengths, y1, colours))
    ], **settings)
Example #7
0
def single_spd_plot(spd, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs):
    """
    Plots given spectral power distribution.

    Parameters
    ----------
    spd : SpectralPowerDistribution
        Spectral power distribution to plot.
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.
    \*\*kwargs : \*\*
        Keywords arguments.

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

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> spd = SpectralPowerDistribution('Custom', data)
    >>> single_spd_plot(spd)  # doctest: +SKIP
    True
    """

    cmfs = get_cmfs(cmfs)

    shape = cmfs.shape
    spd = spd.clone().interpolate(shape, 'Linear')
    wavelengths = spd.wavelengths

    colours = []
    y1 = []

    for wavelength, value in spd:
        XYZ = wavelength_to_XYZ(wavelength, cmfs)
        colours.append(XYZ_to_sRGB(XYZ))
        y1.append(value)

    colours = normalise(colours)

    settings = {
        'title': '{0} - {1}'.format(spd.title, cmfs.title),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Power Distribution',
        'x_tighten': True,
        'x_ticker': True,
        'y_ticker': True}

    settings.update(kwargs)
    return colour_parameters_plot(
        [colour_parameter(x=x[0], y1=x[1], RGB=x[2])
         for x in tuple(zip(wavelengths, y1, colours))],
        **settings)
Example #8
0
def visible_spectrum_plot(cmfs='CIE 1931 2 Degree Standard Observer',
                          out_of_gamut_clipping=True,
                          **kwargs):
    """
    Plots the visible colours spectrum using given standard observer *CIE XYZ*
    colour matching functions.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectrum creation.
    out_of_gamut_clipping : bool, optional
        Out of gamut colours will be clipped if *True* otherwise, the colours
        will be offset by the absolute minimal colour leading to a rendering on
        gray background, less saturated and smoother. [1]_
    \**kwargs : dict, optional
        Keywords arguments.

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

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

    cmfs = get_cmfs(cmfs)
    cmfs = cmfs.clone().align(DEFAULT_SPECTRAL_SHAPE)

    wavelengths = cmfs.shape.range()

    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))

    settings = {
        'title': 'The Visible Spectrum - {0}'.format(cmfs.title),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': False,
        'x_tighten': True,
        'y_ticker': False
    }
    settings.update(kwargs)

    return colour_parameters_plot([
        ColourParameter(x=x[0], RGB=x[1])
        for x in tuple(zip(wavelengths, colours))
    ], **settings)
Example #9
0
def visible_spectrum_plot(cmfs='CIE 1931 2 Degree Standard Observer',
                          out_of_gamut_clipping=True,
                          **kwargs):
    """
    Plots the visible colours spectrum using given standard observer *CIE XYZ*
    colour matching functions.

    Parameters
    ----------
    cmfs : unicode, optional
        Standard observer colour matching functions used for spectrum creation.
    out_of_gamut_clipping : bool, optional
        Out of gamut colours will be clipped if *True* otherwise, the colours
        will be offset by the absolute minimal colour leading to a rendering on
        gray background, less saturated and smoother. [1]_
    \**kwargs : dict, optional
        Keywords arguments.

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

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

    cmfs = get_cmfs(cmfs)
    cmfs = cmfs.clone().align(DEFAULT_SPECTRAL_SHAPE)

    wavelengths = cmfs.shape.range()

    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))

    settings = {
        'title': 'The Visible Spectrum - {0}'.format(cmfs.title),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': False,
        'x_tighten': True,
        'y_ticker': False}
    settings.update(kwargs)

    return colour_parameters_plot([ColourParameter(x=x[0], RGB=x[1])
                                   for x in tuple(zip(wavelengths, colours))],
                                  **settings)
Example #10
0
    def test_wavelength_to_XYZ(self):
        """
        Tests
        :func:`colour.colorimetry.tristimulus.wavelength_to_XYZ` definition.
        """

        np.testing.assert_almost_equal(wavelength_to_XYZ(
            480, CMFS.get('CIE 1931 2 Degree Standard Observer')),
                                       np.array([0.09564, 0.13902, 0.81295]),
                                       decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(480,
                              CMFS.get('CIE 2012 2 Degree Standard Observer')),
            np.array([0.08182895, 0.1788048, 0.7552379]),
            decimal=7)

        np.testing.assert_almost_equal(wavelength_to_XYZ(
            641.5, CMFS.get('CIE 2012 2 Degree Standard Observer')),
                                       np.array([0.44575583, 0.18184213, 0.]),
                                       decimal=7)
def add_rainbow(axis, wavelengths, values, opacity=100):
    # sanity check:
    if not hasattr(axis, 'plot') and not hasattr(axis, 'add_patch'):
        raise Exception("ERROR:\tFirst argument needs to have method \"plot\".")

    from colour.plotting import XYZ_to_plotting_colourspace, filter_cmfs, CONSTANTS_COLOUR_STYLE
    from colour.colorimetry import CCS_ILLUMINANTS, wavelength_to_XYZ
    from colour.utilities import first_item, normalise_maximum
    from matplotlib.patches import Polygon

    col_map_f = "CIE 1931 2 Degree Standard Observer"

    cmfs = first_item(filter_cmfs(col_map_f).values())
    wlen_cmfs = [n for n in wavelengths if n > cmfs.shape.start and n < cmfs.shape.end]

    clr = XYZ_to_plotting_colourspace(
        wavelength_to_XYZ(wlen_cmfs, cmfs),
        CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['E'],
        apply_cctf_encoding=False)

    clr = normalise_maximum(clr)
    clr = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(clr)

    polygon = Polygon(
        np.vstack([
            [min(wavelengths), 0],
            np.array([wavelengths, values]).T.tolist(),
            [max(wavelengths), 0],
        ]),
        facecolor='none',
        edgecolor='none')
    axis.add_patch(polygon)

    if opacity < 100:
        padding = 0
    else:
        padding = 0.1

    for dom, col in [(wavelengths - padding, 'black'), (wlen_cmfs, clr)]:
        axis.bar(
            x=dom,
            height=max(values),
            width=1 + padding,
            color=col,
            align='edge',
            alpha=opacity/100,
            clip_path=polygon
        )

    pass
Example #12
0
def visible_spectrum_plot(cmfs='CIE 1931 2 Degree Standard Observer',
                          **kwargs):
    """
    Plots the visible colours spectrum using given standard observer *CIE XYZ*
    colour matching functions.

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

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

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

    cmfs, name = get_cmfs(cmfs), cmfs
    cmfs = cmfs.clone().align(DEFAULT_SPECTRAL_SHAPE)

    wavelengths = cmfs.shape.range()

    colours = []
    for i in wavelengths:
        XYZ = wavelength_to_XYZ(i, cmfs)
        colours.append(XYZ_to_sRGB(XYZ))

    colours = np.array([np.ravel(x) for x in colours])
    colours *= 1 / np.max(colours)
    colours = np.clip(colours, 0, 1)

    settings = {
        'title': 'The Visible Spectrum - {0}'.format(name),
        'x_label': u'Wavelength λ (nm)',
        'x_tighten': True
    }
    settings.update(kwargs)

    return colour_parameters_plot([
        colour_parameter(x=x[0], RGB=x[1])
        for x in tuple(zip(wavelengths, colours))
    ], **settings)
Example #13
0
def find_colour_single(wl):
    import colour
    from colour.colorimetry import wavelength_to_XYZ

    if wl < 360 or wl > 830:
        RGB = (0, 0, 0)
    else:
        XYZ = wavelength_to_XYZ(wl)
        RGB = colour.XYZ_to_sRGB(XYZ)
        for i in range(0, 3, 1):
            if RGB[i] < 0:
                RGB[i] = 0
            if RGB[i] > 1:
                RGB[i] = 1
    return (RGB)
Example #14
0
def visible_spectrum_plot(cmfs='CIE 1931 2 Degree Standard Observer',
                          **kwargs):
    """
    Plots the visible colours spectrum using given standard observer *CIE XYZ*
    colour matching functions.

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

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

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

    cmfs = get_cmfs(cmfs)
    cmfs = cmfs.clone().align(DEFAULT_SPECTRAL_SHAPE)

    wavelengths = cmfs.shape.range()

    colours = []
    for i in wavelengths:
        XYZ = wavelength_to_XYZ(i, cmfs)
        colours.append(XYZ_to_sRGB(XYZ))

    colours = np.array([np.ravel(x) for x in colours])
    colours *= 1 / np.max(colours)
    colours = np.clip(colours, 0, 1)

    settings = {
        'title': 'The Visible Spectrum - {0}'.format(cmfs.title),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'x_tighten': True}
    settings.update(kwargs)

    return colour_parameters_plot([colour_parameter(x=x[0], RGB=x[1])
                                   for x in tuple(zip(wavelengths, colours))],
                                  **settings)
Example #15
0
    def test_wavelength_to_XYZ(self):
        """
        Tests :func:`colour.colorimetry.tristimulus.wavelength_to_XYZ`
        definition.
        """

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480,
                CMFS.get('CIE 1931 2 Degree Standard Observer')),
            np.array([0.09564, 0.13902, 0.81295]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480,
                CMFS.get('CIE 2012 2 Degree Standard Observer')),
            np.array([0.08182895, 0.1788048, 0.7552379]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                641.5,
                CMFS.get('CIE 2012 2 Degree Standard Observer')),
            np.array([0.44575583, 0.18184213, 0.]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480.5,
                CMFS.get('CIE 2012 2 Degree Standard Observer'),
                'Cubic Spline'),
            np.array([0.07773422, 0.18148028, 0.7337162]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480.5,
                CMFS.get('CIE 2012 2 Degree Standard Observer'),
                'Linear'),
            np.array([0.07779856, 0.18149335, 0.7340129]),
            decimal=7)

        np.testing.assert_almost_equal(
            wavelength_to_XYZ(
                480.5,
                CMFS.get('CIE 2012 2 Degree Standard Observer'),
                'Pchip'),
            np.array([0.07773515, 0.18148048, 0.73372294]),
            decimal=7)
Example #16
0
def plot_single_sd(sd,
                   cmfs='CIE 1931 2 Degree Standard Observer',
                   out_of_gamut_clipping=True,
                   modulate_colours_with_sd_amplitude=False,
                   equalize_sd_amplitude=False,
                   **kwargs):
    """
    Plots given spectral distribution.

    Parameters
    ----------
    sd : SpectralDistribution
        Spectral 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.
    modulate_colours_with_sd_amplitude : bool, optional
        Whether to modulate the colours with the spectral distribution
        amplitude.
    equalize_sd_amplitude : bool, optional
        Whether to equalize the spectral distribution amplitude.
        Equalization occurs after the colours modulation thus setting both
        arguments to *True* will generate a spectrum strip where each
        wavelength colour is modulated by the spectral distribution amplitude.
        The usual 5% margin above the spectral distribution is also omitted.
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.

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

    Returns
    -------
    tuple
        Current figure and axes.

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

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

    .. image:: ../_static/Plotting_Plot_Single_SD.png
        :align: center
        :alt: plot_single_sd
    """

    _figure, axes = artist(**kwargs)

    cmfs = first_item(filter_cmfs(cmfs).values())

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

    colours = XYZ_to_plotting_colourspace(
        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 = normalise_maximum(colours)

    if modulate_colours_with_sd_amplitude:
        colours *= (values / np.max(values))[..., np.newaxis]

    colours = COLOUR_STYLE_CONSTANTS.colour.colourspace.encoding_cctf(colours)

    if equalize_sd_amplitude:
        values = np.ones(values.shape)

    margin = 0 if equalize_sd_amplitude else 0.05

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

    polygon = Polygon(
        np.vstack([
            (x_min, 0),
            tstack([wavelengths, values]),
            (x_max, 0),
        ]),
        facecolor='none',
        edgecolor='none')
    axes.add_patch(polygon)

    padding = 0.1
    axes.bar(
        x=wavelengths - padding,
        height=max(values),
        width=1 + padding,
        color=colours,
        align='edge',
        clip_path=polygon)

    axes.plot(wavelengths, values, color=COLOUR_STYLE_CONSTANTS.colour.dark)

    settings = {
        'axes': axes,
        'bounding_box': (x_min, x_max, y_min, y_max),
        'title': '{0} - {1}'.format(sd.strict_name, cmfs.strict_name),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Distribution',
    }
    settings.update(kwargs)

    return render(**settings)
Example #17
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
        Out of gamut colours will be clipped if *True* otherwise, the colours
        will be offset by the absolute minimal colour leading to a rendering on
        gray background, less saturated and smoother. [1]_
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.
    \**kwargs : dict, optional
        Keywords arguments.

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

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> spd = SpectralPowerDistribution('Custom', data)
    >>> single_spd_plot(spd)  # doctest: +SKIP
    """

    cmfs = get_cmfs(cmfs)

    shape = cmfs.shape
    spd = spd.clone().interpolate(shape, 'Linear')
    wavelengths = spd.wavelengths
    values = spd.values

    y1 = values
    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))

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

    settings.update(kwargs)

    return colour_parameters_plot([
        ColourParameter(x=x[0], y1=x[1], RGB=x[2])
        for x in tuple(zip(wavelengths, y1, colours))
    ], **settings)
Example #18
0
def plot_with_rainbow_fill(ax=None,
                           wavelength=None,
                           flux=None,
                           cmfs="CIE 1931 2 Degree Standard Observer",
                           rainbowtop=np.inf,
                           **kwargs):
    """
    (This is still *real* blarg-y*.)
    Plot a spectrum, with a rainbow underneath.

    Parameters
    ----------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow should be drawn.
    cmfs : string
        The color matching function(s?) to use.

    Returns
    -------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow was drawn.
    """

    if ax is None:
        ax = plt.gca()

    if wavelength is None:
        # create a grid of wavelengths (at which CMFss are useful)
        wavelength = CMFs.wavelengths

    # create y values that will be plotted (these could be spectrum)
    if flux is None:
        flux = np.ones_like(wavelength)

    # pull out only the values that *can* be converted to colors
    ok = (wavelength >= np.min(CMFs.wavelengths)) & (wavelength <= np.max(
        CMFs.wavelengths))

    w, f = wavelength[ok], flux[ok]

    # clip the top of the box?
    f = np.minimum(f, rainbowtop)

    XYZ = wavelength_to_XYZ(w)

    # create colors at theose wavelengths
    colours = XYZ_to_plotting_colourspace(XYZ)

    # normalize the colors to their maximum?
    # colours = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(
    #    normalise_maximum(colours))
    colours = np.maximum(0, colours / np.max(colours))

    x_min, x_max = min(w), max(w)
    y_min, y_max = 0, max(f) + max(f) * 0.05

    # create a polygon to define the top of the bars?
    polygon = Polygon(
        np.vstack([
            (x_min, 0),
            tstack([w, f]),
            (x_max, 0),
        ]),
        facecolor="none",
        edgecolor="none",
    )
    ax.add_patch(polygon)

    # draw bars, with the colors at each vertical stripe
    padding = 0.0
    dw = np.mean(np.diff(w))
    ax.bar(
        x=w,
        height=f,
        width=dw,
        color=colours,
        clip_path=polygon,
        align="edge",
        clip_on=True,
    )

    return ax
Example #19
0
def plot_as_slit_rainbow(ax=None,
                         wavelength=None,
                         flux=None,
                         cmfs="CIE 1931 2 Degree Standard Observer",
                         **kwargs):
    """
    (This is still *real* blarg-y*.)
    Plot a spectrum as a light source would be seen through
    a slit spectrometer, with vertical bands of light that
    are brighter or fainter depending on the intensity
    of the spectrum at that particular wavelength.

    Parameters
    ----------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow should be drawn.

    wavelength : array
        The wavelengths to include in the spectrum.
        In units of nm, but not as astropy units.

    flux : array
        The fluxes to include in the spectrum.
        In units of whatever, but not as astropy units.

    cmfs : string
        The color matching function(s?) to use.

    vector : bool


    Returns
    -------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow was drawn.
    """

    # make sure our plotting ax is defined
    if ax is None:
        ax = plt.gca()

    # make sure we have a grid of wavelengths defined
    if wavelength is None:
        # create a grid of wavelengths (at which CMFss are useful)
        wavelength = CMFs.wavelengths

    # create y values that will be plotted (these could be spectrum)
    if flux is None:
        flux = np.ones_like(wavelength)

    # pull out only the values that *can* be converted to colors
    ok = (wavelength >= np.min(CMFs.wavelengths)) & (wavelength <= np.max(
        CMFs.wavelengths))
    w, f = wavelength[ok], flux[ok]

    # get the XYZ for the wavelengths
    XYZ = wavelength_to_XYZ(w)

    # create colors at those wavelengths
    colours = XYZ_to_plotting_colourspace(XYZ)

    # normalize the colors to their maximum?
    # colours = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(
    #    normalise_maximum(colours))

    # normalize the brightness by the flux
    colours *= f[:, np.newaxis]

    # normalize to the brightest line
    colours = np.maximum(0, colours / np.max(colours))

    # draw as an RGB color image with imshow
    ax.imshow(
        colours[np.newaxis, :, :],
        aspect="auto",
        extent=[np.min(w), np.max(w), 0, 1],
        interpolation="nearest",
    )

    return ax
Example #20
0
def plot_simple_rainbow(ax=None,
                        wavelength=None,
                        flux=None,
                        cmfs="CIE 1931 2 Degree Standard Observer",
                        **kwargs):
    """
    Plot a simple horizontal rainbow,
    based off colour's plot_single_sd.

    Parameters
    ----------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow should be drawn.
    cmfs : string
        The color matching function(s?) to use.

    Returns
    -------
    ax : matplotlib.axes._subplots.AxesSubplot
        The ax into which the rainbow was drawn.
    """

    if ax is None:
        ax = plt.gca()

    # pull out the CMFss
    cmfs = first_item(filter_cmfs(cmfs).values())

    if wavelength is None:
        # create a grid of wavelengths (at which CMFss are useful)
        wavelength = cmfs.wavelengths

    ok = (wavelength >= np.min(cmfs.wavelengths)) & (wavelength <= np.max(
        cmfs.wavelengths))

    # create colors at theose wavelengths
    colours = XYZ_to_plotting_colourspace(
        wavelength_to_XYZ(wavelength[ok], cmfs),
        CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["E"],
    )

    # normalize the colors to their maximum?
    colours = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(
        normalise_maximum(colours))

    # create y values that will be plotted (these could be spectrum)
    if flux is None:
        flux = np.ones_like(wavelength)
    x_min, x_max = min(wavelength), max(wavelength)
    y_min, y_max = 0, max(flux) + max(flux) * 0.05

    # create a polygon to define the top of the bars?
    polygon = Polygon(
        np.vstack([
            (x_min, 0),
            tstack([wavelength[ok], flux[ok]]),
            (x_max, 0),
        ]),
        facecolor="none",
        edgecolor="none",
    )
    ax.add_patch(polygon)

    # draw bars, with the colors at each vertical stripe
    padding = 0.2
    ax.bar(
        x=wavelength[ok] - padding / 2,
        height=max(flux[ok]),
        width=1 + padding,
        color=colours,
        align="edge",
    )

    return ax
Example #21
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
        Out of gamut colours will be clipped if *True* otherwise, the colours
        will be offset by the absolute minimal colour leading to a rendering on
        gray background, less saturated and smoother. [1]_
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.
    \**kwargs : dict, optional
        Keywords arguments.

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

    Examples
    --------
    >>> from colour import SpectralPowerDistribution
    >>> data = {400: 0.0641, 420: 0.0645, 440: 0.0562}
    >>> spd = SpectralPowerDistribution('Custom', data)
    >>> single_spd_plot(spd)  # doctest: +SKIP
    True
    """

    cmfs = get_cmfs(cmfs)

    shape = cmfs.shape
    spd = spd.clone().interpolate(shape, 'Linear')
    wavelengths = spd.wavelengths
    values = spd.values

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

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

    colours = DEFAULT_PLOTTING_OECF(normalise(colours))

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

    settings.update(kwargs)

    return colour_parameters_plot(
        [ColourParameter(x=x[0], y1=x[1], RGB=x[2])
         for x in tuple(zip(wavelengths, y1, colours))],
        **settings)
Example #22
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 #23
0
def plot_single_sd(sd,
                   cmfs='CIE 1931 2 Degree Standard Observer',
                   out_of_gamut_clipping=True,
                   modulate_colours_with_sd_amplitude=False,
                   equalize_sd_amplitude=False,
                   **kwargs):
    """
    Plots given spectral distribution.

    Parameters
    ----------
    sd : SpectralDistribution
        Spectral 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.
    modulate_colours_with_sd_amplitude : bool, optional
        Whether to modulate the colours with the spectral distribution
        amplitude.
    equalize_sd_amplitude : bool, optional
        Whether to equalize the spectral distribution amplitude.
        Equalization occurs after the colours modulation thus setting both
        arguments to *True* will generate a spectrum strip where each
        wavelength colour is modulated by the spectral distribution amplitude.
        The usual 5% margin above the spectral distribution is also omitted.
    cmfs : unicode
        Standard observer colour matching functions used for spectrum creation.

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

    Returns
    -------
    tuple
        Current figure and axes.

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

    Examples
    --------
    >>> from colour import SpectralDistribution
    >>> data = {
    ...     500: 0.0651,
    ...     520: 0.0705,
    ...     540: 0.0772,
    ...     560: 0.0870,
    ...     580: 0.1128,
    ...     600: 0.1360
    ... }
    >>> sd = SpectralDistribution(data, name='Custom')
    >>> plot_single_sd(sd)  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, \
<matplotlib.axes._subplots.AxesSubplot object at 0x...>)

    .. image:: ../_static/Plotting_Plot_Single_SD.png
        :align: center
        :alt: plot_single_sd
    """

    _figure, axes = artist(**kwargs)

    cmfs = first_item(filter_cmfs(cmfs).values())

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

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

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

    colours = normalise_maximum(colours)

    if modulate_colours_with_sd_amplitude:
        colours *= (values / np.max(values))[..., np.newaxis]

    colours = COLOUR_STYLE_CONSTANTS.colour.colourspace.cctf_encoding(colours)

    if equalize_sd_amplitude:
        values = np.ones(values.shape)

    margin = 0 if equalize_sd_amplitude else 0.05

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

    polygon = Polygon(np.vstack([
        (x_min, 0),
        tstack([wavelengths, values]),
        (x_max, 0),
    ]),
                      facecolor='none',
                      edgecolor='none')
    axes.add_patch(polygon)

    padding = 0.1
    axes.bar(x=wavelengths - padding,
             height=max(values),
             width=1 + padding,
             color=colours,
             align='edge',
             clip_path=polygon)

    axes.plot(wavelengths, values, color=COLOUR_STYLE_CONSTANTS.colour.dark)

    settings = {
        'axes': axes,
        'bounding_box': (x_min, x_max, y_min, y_max),
        'title': '{0} - {1}'.format(sd.strict_name, cmfs.strict_name),
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Distribution',
    }
    settings.update(kwargs)

    return render(**settings)
Example #24
0
def plot_single_sd(
    sd: SpectralDistribution,
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    out_of_gamut_clipping: Boolean = True,
    modulate_colours_with_sd_amplitude: Boolean = False,
    equalize_sd_amplitude: Boolean = False,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given spectral distribution.

    Parameters
    ----------
    sd
        Spectral distribution to plot.
    cmfs
        Standard observer colour matching functions used for computing the
        spectrum domain and colours. ``cmfs`` can be of any type or form
        supported by the :func:`colour.plotting.filter_cmfs` definition.
    out_of_gamut_clipping
        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.
    modulate_colours_with_sd_amplitude
        Whether to modulate the colours with the spectral distribution
        amplitude.
    equalize_sd_amplitude
        Whether to equalize the spectral distribution amplitude.
        Equalization occurs after the colours modulation thus setting both
        arguments to *True* will generate a spectrum strip where each
        wavelength colour is modulated by the spectral distribution amplitude.
        The usual 5% margin above the spectral distribution is also omitted.

    Other Parameters
    ----------------
    kwargs
        {:func:`colour.plotting.artist`, :func:`colour.plotting.render`},
        See the documentation of the previously listed definitions.

    Returns
    -------
    :class:`tuple`
        Current figure and axes.

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

    Examples
    --------
    >>> from colour import SpectralDistribution
    >>> data = {
    ...     500: 0.0651,
    ...     520: 0.0705,
    ...     540: 0.0772,
    ...     560: 0.0870,
    ...     580: 0.1128,
    ...     600: 0.1360
    ... }
    >>> sd = SpectralDistribution(data, name='Custom')
    >>> plot_single_sd(sd)  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Single_SD.png
        :align: center
        :alt: plot_single_sd
    """

    _figure, axes = artist(**kwargs)

    cmfs = cast(MultiSpectralDistributions,
                first_item(filter_cmfs(cmfs).values()))

    sd = cast(SpectralDistribution, sd.copy())
    sd.interpolator = LinearInterpolator
    wavelengths = cmfs.wavelengths[np.logical_and(
        cmfs.wavelengths >= max(min(cmfs.wavelengths), min(sd.wavelengths)),
        cmfs.wavelengths <= min(max(cmfs.wavelengths), max(sd.wavelengths)),
    )]
    values = as_float_array(sd[wavelengths])

    RGB = XYZ_to_plotting_colourspace(
        wavelength_to_XYZ(wavelengths, cmfs),
        CCS_ILLUMINANTS["CIE 1931 2 Degree Standard Observer"]["E"],
        apply_cctf_encoding=False,
    )

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

    RGB = normalise_maximum(RGB)

    if modulate_colours_with_sd_amplitude:
        RGB *= (values / np.max(values))[..., np.newaxis]

    RGB = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(RGB)

    if equalize_sd_amplitude:
        values = ones(values.shape)

    margin = 0 if equalize_sd_amplitude else 0.05

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

    polygon = Polygon(
        np.vstack([
            (x_min, 0),
            tstack([wavelengths, values]),
            (x_max, 0),
        ]),
        facecolor="none",
        edgecolor="none",
        zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
    )
    axes.add_patch(polygon)

    padding = 0.1
    axes.bar(
        x=wavelengths - padding,
        height=max(values),
        width=1 + padding,
        color=RGB,
        align="edge",
        clip_path=polygon,
        zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
    )

    axes.plot(
        wavelengths,
        values,
        color=CONSTANTS_COLOUR_STYLE.colour.dark,
        zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_line,
    )

    settings: Dict[str, Any] = {
        "axes": axes,
        "bounding_box": (x_min, x_max, y_min, y_max),
        "title": f"{sd.strict_name} - {cmfs.strict_name}",
        "x_label": "Wavelength $\\lambda$ (nm)",
        "y_label": "Spectral Distribution",
    }
    settings.update(kwargs)

    return render(**settings)