Ejemplo n.º 1
0
    def test_filter_illuminants(self):
        """Test :func:`colour.plotting.common.filter_illuminants` definition."""

        self.assertListEqual(
            sorted(filter_illuminants(["^D.*"]).keys()),
            ["D50", "D55", "D60", "D65", "D75", "Daylight FL"],
        )
Ejemplo n.º 2
0
    def test_filter_illuminants(self):
        """
        Tests :func:`colour.plotting.common.filter_illuminants` definition.
        """

        self.assertListEqual(
            sorted(filter_illuminants(['^D.*']).keys()),
            ['D50', 'D55', 'D60', 'D65', 'D75', 'Daylight FL'])
Ejemplo n.º 3
0
def plot_single_illuminant_sd(
    illuminant: Union[SpectralDistribution, str],
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given single illuminant spectral distribution.

    Parameters
    ----------
    illuminant
        Illuminant to plot. ``illuminant`` can be of any type or form supported
        by the :func:`colour.plotting.filter_illuminants` definition.
    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.

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

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

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

    Examples
    --------
    >>> plot_single_illuminant_sd('A')  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Single_Illuminant_SD.png
        :align: center
        :alt: plot_single_illuminant_sd
    """

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

    title = f"Illuminant {illuminant} - {cmfs.strict_name}"

    illuminant = first_item(filter_illuminants(illuminant).values())

    settings: Dict[str, Any] = {"title": title, "y_label": "Relative Power"}
    settings.update(kwargs)

    return plot_single_sd(illuminant, **settings)
Ejemplo n.º 4
0
def plot_single_illuminant_sd(illuminant,
                              cmfs='CIE 1931 2 Degree Standard Observer',
                              **kwargs):
    """
    Plots given single illuminant spectral distribution.

    Parameters
    ----------
    illuminant : unicode or LMS_ConeFundamentals or \
RGB_ColourMatchingFunctions or XYZ_ColourMatchingFunctions, optional
        Illuminant to plot. ``illuminant`` can be of any type or form supported
        by the :func:`colour.plotting.filter_illuminants` definition.
    cmfs : unicode or XYZ_ColourMatchingFunctions, optional
        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.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_single_sd`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
    out_of_gamut_clipping : bool, optional
        {:func:`colour.plotting.plot_single_sd`},
        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.

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

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

    Examples
    --------
    >>> plot_single_illuminant_sd('A')  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Single_Illuminant_SD.png
        :align: center
        :alt: plot_single_illuminant_sd
    """

    cmfs = first_item(filter_cmfs(cmfs).values())
    title = 'Illuminant {0} - {1}'.format(illuminant, cmfs.strict_name)

    illuminant = first_item(filter_illuminants(illuminant).values())

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_single_sd(illuminant, **settings)
Ejemplo n.º 5
0
def plot_single_illuminant_sd(illuminant='A',
                              cmfs='CIE 1931 2 Degree Standard Observer',
                              **kwargs):
    """
    Plots given single illuminant spectral distribution.

    Parameters
    ----------
    illuminant : unicode, optional
        Factory illuminant to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions to plot.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_single_sd`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
    out_of_gamut_clipping : bool, optional
        {:func:`colour.plotting.plot_single_sd`},
        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.

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

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

    Examples
    --------
    >>> plot_single_illuminant_sd('A')  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_Single_Illuminant_SD.png
        :align: center
        :alt: plot_single_illuminant_sd
    """

    cmfs = first_item(filter_cmfs(cmfs).values())
    title = 'Illuminant {0} - {1}'.format(illuminant, cmfs.strict_name)

    illuminant = first_item(filter_illuminants(illuminant).values())

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_single_sd(illuminant, **settings)
Ejemplo n.º 6
0
def plot_single_illuminant_sd(illuminant='A',
                              cmfs='CIE 1931 2 Degree Standard Observer',
                              **kwargs):
    """
    Plots given single illuminant spectral distribution.

    Parameters
    ----------
    illuminant : unicode, optional
        Factory illuminant to plot.
    cmfs : unicode, optional
        Standard observer colour matching functions to plot.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_single_sd`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
    out_of_gamut_clipping : bool, optional
        {:func:`colour.plotting.plot_single_sd`},
        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.

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

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

    Examples
    --------
    >>> plot_single_illuminant_sd('A')  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_Single_Illuminant_SD.png
        :align: center
        :alt: plot_single_illuminant_sd
    """

    cmfs = first_item(filter_cmfs(cmfs).values())
    title = 'Illuminant {0} - {1}'.format(illuminant, cmfs.strict_name)

    illuminant = first_item(filter_illuminants(illuminant).values())

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_single_sd(illuminant, **settings)
Ejemplo n.º 7
0
def plot_multi_illuminant_sds(illuminants, **kwargs):
    """
    Plots given illuminants spectral distributions.

    Parameters
    ----------
    illuminants : unicode or SpectralDistribution or array_like
        Illuminants to plot. ``illuminants`` elements can be of any type or
        form supported by the :func:`colour.plotting.filter_illuminants`
        definition.

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

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

    Examples
    --------
    >>> plot_multi_illuminant_sds(['A', 'B', 'C'])  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Multi_Illuminant_SDS.png
        :align: center
        :alt: plot_multi_illuminant_sds
    """

    if 'plot_kwargs' not in kwargs:
        kwargs['plot_kwargs'] = {}

    SD_E = SDS_ILLUMINANTS['E']
    if isinstance(kwargs['plot_kwargs'], dict):
        kwargs['plot_kwargs']['illuminant'] = SD_E
    else:
        for i in range(len(kwargs['plot_kwargs'])):
            kwargs['plot_kwargs'][i]['illuminant'] = SD_E

    illuminants = filter_illuminants(illuminants).values()

    title = '{0} - Illuminants Spectral Distributions'.format(', '.join(
        [illuminant.strict_name for illuminant in illuminants]))

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_multi_sds(illuminants, **settings)
Ejemplo n.º 8
0
def plot_multi_illuminant_sds(illuminants=None, **kwargs):
    """
    Plots given illuminants spectral distributions.

    Parameters
    ----------
    illuminants : array_like, optional
        Factory illuminants to plot.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_multi_sds`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
    use_sds_colours : bool, optional
        {:func:`colour.plotting.plot_multi_sds`}
        Whether to use spectral distributions colours.
    normalise_sds_colours : bool
        {:func:`colour.plotting.plot_multi_sds`}
        Whether to normalise spectral distributions colours.

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

    Examples
    --------
    >>> plot_multi_illuminant_sds(['A', 'B', 'C'])  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, \
<matplotlib.axes._subplots.AxesSubplot object at 0x...>)

    .. image:: ../_static/Plotting_Plot_Multi_Illuminant_SDS.png
        :align: center
        :alt: plot_multi_illuminant_sds
    """

    if illuminants is None:
        illuminants = ('A', 'B', 'C')

    illuminants = filter_illuminants(illuminants).values()

    title = '{0} - Illuminants Spectral Distributions'.format(', '.join(
        [illuminant.strict_name for illuminant in illuminants]))

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_multi_sds(illuminants, **settings)
Ejemplo n.º 9
0
def plot_multi_illuminant_sds(illuminants=None, **kwargs):
    """
    Plots given illuminants spectral distributions.

    Parameters
    ----------
    illuminants : array_like, optional
        Factory illuminants to plot.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.plot_multi_sds`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
    use_sds_colours : bool, optional
        {:func:`colour.plotting.plot_multi_sds`}
        Whether to use spectral distributions colours.
    normalise_sds_colours : bool
        {:func:`colour.plotting.plot_multi_sds`}
        Whether to normalise spectral distributions colours.

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

    Examples
    --------
    >>> plot_multi_illuminant_sds(['A', 'B', 'C'])  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_Multi_Illuminant_SDs.png
        :align: center
        :alt: plot_multi_illuminant_sds
    """

    if illuminants is None:
        illuminants = ('A', 'B', 'C')

    illuminants = filter_illuminants(illuminants).values()

    title = '{0} - Illuminants Spectral Distributions'.format(', '.join(
        [illuminant.strict_name for illuminant in illuminants]))

    settings = {'title': title, 'y_label': 'Relative Power'}
    settings.update(kwargs)

    return plot_multi_sds(illuminants, **settings)
Ejemplo n.º 10
0
def plot_visible_spectrum_section(
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    illuminant: Union[SpectralDistribution, str] = "D65",
    model: Union[Literal["CAM02LCD", "CAM02SCD", "CAM02UCS", "CAM16LCD",
                         "CAM16SCD", "CAM16UCS", "CIE XYZ", "CIE xyY",
                         "CIE Lab", "CIE Luv", "CIE UCS", "CIE UVW", "DIN99",
                         "Hunter Lab", "Hunter Rdab", "ICaCb", "ICtCp", "IPT",
                         "IgPgTg", "Jzazbz", "OSA UCS", "Oklab", "hdr-CIELAB",
                         "hdr-IPT", ], str, ] = "CIE xyY",
    axis: Union[Literal["+z", "+x", "+y"], str] = "+z",
    origin: Floating = 0.5,
    normalise: Boolean = True,
    show_section_colours: Boolean = True,
    show_section_contour: Boolean = True,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot the visible spectrum volume, i.e. *Rösch-MacAdam* colour solid,
    section colours along given axis and origin.

    Parameters
    ----------
    cmfs
        Standard observer colour matching functions, default to the
        *CIE 1931 2 Degree Standard Observer*.  ``cmfs`` can be of any type or
        form supported by the :func:`colour.plotting.filter_cmfs` definition.
    illuminant
        Illuminant spectral distribution, default to *CIE Illuminant D65*.
        ``illuminant`` can be of any type or form supported by the
        :func:`colour.plotting.filter_illuminants` definition.
    model
        Colourspace model, see :attr:`colour.COLOURSPACE_MODELS` attribute for
        the list of supported colourspace models.
    axis
        Axis the hull section will be normal to.
    origin
        Coordinate along ``axis`` at which to plot the hull section.
    normalise
        Whether to normalise ``axis`` to the extent of the hull along it.
    show_section_colours
        Whether to show the hull section colours.
    show_section_contour
        Whether to show the hull section contour.

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

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

    Examples
    --------
    >>> from colour.utilities import is_trimesh_installed
    >>> if is_trimesh_installed:
    ...     plot_visible_spectrum_section(
    ...         section_colours='RGB', section_opacity=0.15)
    ...     # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Visible_Spectrum_Section.png
        :align: center
        :alt: plot_visible_spectrum_section
    """

    import trimesh

    settings: Dict[str, Any] = {"uniform": True}
    settings.update(kwargs)

    _figure, axes = artist(**settings)

    # pylint: disable=E1102
    cmfs = reshape_msds(first_item(filter_cmfs(cmfs).values()),
                        SpectralShape(360, 780, 1))
    illuminant = cast(
        SpectralDistribution,
        first_item(filter_illuminants(illuminant).values()),
    )

    vertices = solid_RoschMacAdam(
        cmfs,
        illuminant,
        point_order="Pulse Wave Width",
        filter_jagged_points=True,
    )
    mesh = trimesh.Trimesh(vertices)
    hull = trimesh.convex.convex_hull(mesh)

    if show_section_colours:
        settings = {"axes": axes}
        settings.update(kwargs)
        settings["standalone"] = False

        plot_hull_section_colours(hull, model, axis, origin, normalise,
                                  **settings)

    if show_section_contour:
        settings = {"axes": axes}
        settings.update(kwargs)
        settings["standalone"] = False

        plot_hull_section_contour(hull, model, axis, origin, normalise,
                                  **settings)

    title = (f"Visible Spectrum Section - "
             f"{f'{origin * 100}%' if normalise else origin} - "
             f"{model} - "
             f"{cmfs.strict_name}")

    plane = MAPPING_AXIS_TO_PLANE[axis]

    labels = np.array(COLOURSPACE_MODELS_AXIS_LABELS[model])[as_int_array(
        colourspace_model_axis_reorder([0, 1, 2], model))]
    x_label, y_label = labels[plane[0]], labels[plane[1]]

    settings.update({
        "axes": axes,
        "standalone": True,
        "title": title,
        "x_label": x_label,
        "y_label": y_label,
    })
    settings.update(kwargs)

    return render(**settings)
Ejemplo n.º 11
0
def plot_sds_in_chromaticity_diagram(
        sds,
        cmfs='CIE 1931 2 Degree Standard Observer',
        chromaticity_diagram_callable=plot_chromaticity_diagram,
        method='CIE 1931',
        annotate_kwargs=None,
        plot_kwargs=None,
        **kwargs):
    """
    Plots given spectral distribution chromaticity coordinates into the
    *Chromaticity Diagram* using given method.

    Parameters
    ----------
    sds : array_like or MultiSpectralDistributions
        Spectral distributions or multi-spectral distributions to
        plot. `sds` can be a single
        :class:`colour.MultiSpectralDistributions` class instance, a list
        of :class:`colour.MultiSpectralDistributions` class instances or a
        list of :class:`colour.SpectralDistribution` class instances.
    cmfs : unicode or XYZ_ColourMatchingFunctions, optional
        Standard observer colour matching functions used for computing the
        spectral locus boundaries. ``cmfs`` can be of any type or form
        supported by the :func:`colour.plotting.filter_cmfs` definition.
    chromaticity_diagram_callable : callable, optional
        Callable responsible for drawing the *Chromaticity Diagram*.
    method : unicode, optional
        **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**,
        *Chromaticity Diagram* method.
    annotate_kwargs : dict or array_like, optional
        Keyword arguments for the :func:`plt.annotate` definition, used to
        annotate the resulting chromaticity coordinates with their respective
        spectral distribution names. ``annotate_kwargs`` can be either a single
        dictionary applied to all the arrows with same settings or a sequence
        of dictionaries with different settings for each spectral distribution.
        The following special keyword arguments can also be used:

        -   *annotate* : bool, whether to annotate the spectral distributions.
    plot_kwargs : dict or array_like, optional
        Keyword arguments for the :func:`plt.plot` definition, used to control
        the style of the plotted spectral distributions. ``plot_kwargs`` can be
        either a single dictionary applied to all the plotted spectral
        distributions with same settings or a sequence of dictionaries with
        different settings for each plotted spectral distributions.
        The following special keyword arguments can also be used:

        -   *illuminant* : unicode or :class:`colour.SpectralDistribution`, the
            illuminant used to compute the spectral distributions colours. The
            default is the illuminant associated with the whitepoint of the
            default plotting colourspace. ``illuminant`` can be of any type or
            form supported by the :func:`colour.plotting.filter_cmfs`
            definition.
        -   *cmfs* : unicode, the standard observer colour matching functions
            used for computing the spectral distributions colours. ``cmfs`` can
            be of any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   *normalise_sd_colours* : bool, whether to normalise the computed
            spectral distributions colours. The default is *True*.
        -   *use_sd_colours* : bool, whether to use the computed spectral
            distributions colours under the plotting colourspace illuminant.
            Alternatively, it is possible to use the :func:`plt.plot`
            definition ``color`` argument with pre-computed values. The default
            is *True*.

    Other Parameters
    ----------------
    \\**kwargs : dict, optional
        {:func:`colour.plotting.artist`,
        :func:`colour.plotting.diagrams.plot_chromaticity_diagram`,
        :func:`colour.plotting.render`},
        Please refer to the documentation of the previously listed definitions.
        Also handles keywords arguments for deprecation management.

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

    Examples
    --------
    >>> A = SDS_ILLUMINANTS['A']
    >>> D65 = SDS_ILLUMINANTS['D65']
    >>> annotate_kwargs = [
    ...     {'xytext': (-25, 15), 'arrowprops':{'arrowstyle':'-'}},
    ...     {}
    ... ]
    >>> plot_kwargs = [
    ...     {
    ...         'illuminant': SDS_ILLUMINANTS['E'],
    ...         'markersize' : 15,
    ...         'normalise_sd_colours': True,
    ...         'use_sd_colours': True
    ...     },
    ...     {'illuminant': SDS_ILLUMINANTS['E']},
    ... ]
    >>> plot_sds_in_chromaticity_diagram(
    ...     [A, D65], annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs)
    ... # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_SDS_In_Chromaticity_Diagram.png
        :align: center
        :alt: plot_sds_in_chromaticity_diagram
    """

    annotate_kwargs = handle_arguments_deprecation(
        {
            'ArgumentRenamed': [['annotate_parameters', 'annotate_kwargs']],
        }, **kwargs).get('annotate_kwargs', annotate_kwargs)

    sds = sds_and_msds_to_sds(sds)

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

    _figure, axes = artist(**settings)

    method = method.upper()

    settings.update({
        'axes': axes,
        'standalone': False,
        'method': method,
        'cmfs': cmfs,
    })

    chromaticity_diagram_callable(**settings)

    if method == 'CIE 1931':

        def XYZ_to_ij(XYZ):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return XYZ_to_xy(XYZ)

        bounding_box = (-0.1, 0.9, -0.1, 0.9)
    elif method == 'CIE 1960 UCS':

        def XYZ_to_ij(XYZ):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return UCS_to_uv(XYZ_to_UCS(XYZ))

        bounding_box = (-0.1, 0.7, -0.2, 0.6)

    elif method == 'CIE 1976 UCS':

        def XYZ_to_ij(XYZ):
            """
            Converts given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return Luv_to_uv(XYZ_to_Luv(XYZ))

        bounding_box = (-0.1, 0.7, -0.1, 0.7)
    else:
        raise ValueError(
            'Invalid method: "{0}", must be one of '
            '[\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\']'.format(
                method))

    annotate_settings_collection = [{
        'annotate': True,
        'xytext': (-50, 30),
        'textcoords': 'offset points',
        'arrowprops': CONSTANTS_ARROW_STYLE,
    } for _ in range(len(sds))]

    if annotate_kwargs is not None:
        update_settings_collection(annotate_settings_collection,
                                   annotate_kwargs, len(sds))

    plot_settings_collection = [{
        'color':
        CONSTANTS_COLOUR_STYLE.colour.brightest,
        'label':
        '{0}'.format(sd.strict_name),
        'marker':
        'o',
        'markeredgecolor':
        CONSTANTS_COLOUR_STYLE.colour.dark,
        'markeredgewidth':
        CONSTANTS_COLOUR_STYLE.geometry.short * 0.75,
        'markersize': (CONSTANTS_COLOUR_STYLE.geometry.short * 6 +
                       CONSTANTS_COLOUR_STYLE.geometry.short * 0.75),
        'cmfs':
        cmfs,
        'illuminant':
        SDS_ILLUMINANTS[
            CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint_name],
        'use_sd_colours':
        False,
        'normalise_sd_colours':
        False,
    } for sd in sds]

    if plot_kwargs is not None:
        update_settings_collection(plot_settings_collection, plot_kwargs,
                                   len(sds))

    for i, sd in enumerate(sds):
        plot_settings = plot_settings_collection[i]

        cmfs = first_item(filter_cmfs(plot_settings.pop('cmfs')).values())
        illuminant = first_item(
            filter_illuminants(plot_settings.pop('illuminant')).values())
        normalise_sd_colours = plot_settings.pop('normalise_sd_colours')
        use_sd_colours = plot_settings.pop('use_sd_colours')

        with domain_range_scale('1'):
            XYZ = sd_to_XYZ(sd, cmfs, illuminant)

        if use_sd_colours:
            if normalise_sd_colours:
                XYZ /= XYZ[..., 1]

            plot_settings['color'] = np.clip(XYZ_to_plotting_colourspace(XYZ),
                                             0, 1)

        ij = XYZ_to_ij(XYZ)

        axes.plot(ij[0], ij[1], **plot_settings)

        if (sd.name is not None
                and annotate_settings_collection[i]['annotate']):
            annotate_settings = annotate_settings_collection[i]
            annotate_settings.pop('annotate')

            axes.annotate(sd.name, xy=ij, **annotate_settings)

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

    return render(**settings)
Ejemplo n.º 12
0
def plot_multi_illuminant_sds(
    illuminants: Union[SpectralDistribution, str,
                       Sequence[Union[SpectralDistribution, str]]],
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given illuminants spectral distributions.

    Parameters
    ----------
    illuminants
        Illuminants to plot. ``illuminants`` elements can be of any type or
        form supported by the :func:`colour.plotting.filter_illuminants`
        definition.

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

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

    Examples
    --------
    >>> plot_multi_illuminant_sds(['A', 'B', 'C'])  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Multi_Illuminant_SDS.png
        :align: center
        :alt: plot_multi_illuminant_sds
    """

    if "plot_kwargs" not in kwargs:
        kwargs["plot_kwargs"] = {}

    SD_E = SDS_ILLUMINANTS["E"]
    if isinstance(kwargs["plot_kwargs"], dict):
        kwargs["plot_kwargs"]["illuminant"] = SD_E
    else:
        for i in range(len(kwargs["plot_kwargs"])):
            kwargs["plot_kwargs"][i]["illuminant"] = SD_E

    illuminants = cast(
        List[SpectralDistribution],
        list(filter_illuminants(illuminants).values()),
    )

    illuminant_strict_names = ", ".join(
        [illuminant.strict_name for illuminant in illuminants])
    title = f"{illuminant_strict_names} - Illuminants Spectral Distributions"

    settings: Dict[str, Any] = {"title": title, "y_label": "Relative Power"}
    settings.update(kwargs)

    return plot_multi_sds(illuminants, **settings)
Ejemplo n.º 13
0
def plot_multi_sds(
    sds: Union[Sequence[Union[SpectralDistribution,
                              MultiSpectralDistributions]],
               MultiSpectralDistributions, ],
    plot_kwargs: Optional[Union[Dict, List[Dict]]] = None,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given spectral distributions.

    Parameters
    ----------
    sds
        Spectral distributions or multi-spectral distributions to
        plot. `sds` can be a single
        :class:`colour.MultiSpectralDistributions` class instance, a list
        of :class:`colour.MultiSpectralDistributions` class instances or a
        list of :class:`colour.SpectralDistribution` class instances.
    plot_kwargs
        Keyword arguments for the :func:`matplotlib.pyplot.plot` definition,
        used to control the style of the plotted spectral distributions.
        `plot_kwargs`` can be either a single dictionary applied to all the
        plotted spectral distributions with the same settings or a sequence of
        dictionaries with different settings for each plotted spectral
        distributions. The following special keyword arguments can also be
        used:

        -   ``illuminant`` : The illuminant used to compute the spectral
            distributions colours. The default is the illuminant associated
            with the whitepoint of the default plotting colourspace.
            ``illuminant`` can be of any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   ``cmfs`` : The standard observer colour matching functions used for
            computing the spectral distributions colours. ``cmfs`` can be of
            any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   ``normalise_sd_colours`` : Whether to normalise the computed
            spectral distributions colours. The default is *True*.
        -   ``use_sd_colours`` : Whether to use the computed spectral
            distributions colours under the plotting colourspace illuminant.
            Alternatively, it is possible to use the
            :func:`matplotlib.pyplot.plot` definition ``color`` argument with
            pre-computed values. The default is *True*.

    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.

    Examples
    --------
    >>> from colour import SpectralDistribution
    >>> 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
    ... }
    >>> sd_1 = SpectralDistribution(data_1, name='Custom 1')
    >>> sd_2 = SpectralDistribution(data_2, name='Custom 2')
    >>> plot_kwargs = [
    ...     {'use_sd_colours': True},
    ...     {'use_sd_colours': True, 'linestyle': 'dashed'},
    ... ]
    >>> plot_multi_sds([sd_1, sd_2], plot_kwargs=plot_kwargs)
    ... # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Multi_SDS.png
        :align: center
        :alt: plot_multi_sds
    """

    _figure, axes = artist(**kwargs)

    sds_converted = sds_and_msds_to_sds(sds)

    plot_settings_collection = [{
        "label":
        f"{sd.strict_name}",
        "zorder":
        CONSTANTS_COLOUR_STYLE.zorder.midground_line,
        "cmfs":
        "CIE 1931 2 Degree Standard Observer",
        "illuminant":
        SDS_ILLUMINANTS[
            CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint_name],
        "use_sd_colours":
        False,
        "normalise_sd_colours":
        False,
    } for sd in sds_converted]

    if plot_kwargs is not None:
        update_settings_collection(plot_settings_collection, plot_kwargs,
                                   len(sds_converted))

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for i, sd in enumerate(sds_converted):
        plot_settings = plot_settings_collection[i]

        cmfs = cast(
            MultiSpectralDistributions,
            first_item(filter_cmfs(plot_settings.pop("cmfs")).values()),
        )
        illuminant = cast(
            SpectralDistribution,
            first_item(
                filter_illuminants(plot_settings.pop("illuminant")).values()),
        )
        normalise_sd_colours = plot_settings.pop("normalise_sd_colours")
        use_sd_colours = plot_settings.pop("use_sd_colours")

        wavelengths, values = sd.wavelengths, sd.values

        shape = sd.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_sd_colours:
            with domain_range_scale("1"):
                XYZ = sd_to_XYZ(sd, cmfs, illuminant)

            if normalise_sd_colours:
                XYZ /= XYZ[..., 1]

            plot_settings["color"] = np.clip(XYZ_to_plotting_colourspace(XYZ),
                                             0, 1)

        axes.plot(wavelengths, values, **plot_settings)

    bounding_box = (
        min(x_limit_min),
        max(x_limit_max),
        min(y_limit_min),
        max(y_limit_max) + np.max(y_limit_max) * 0.05,
    )
    settings: Dict[str, Any] = {
        "axes": axes,
        "bounding_box": bounding_box,
        "legend": True,
        "x_label": "Wavelength $\\lambda$ (nm)",
        "y_label": "Spectral Distribution",
    }
    settings.update(kwargs)

    return render(**settings)
Ejemplo n.º 14
0
def plot_sds_in_chromaticity_diagram(
    sds: Union[Sequence[Union[SpectralDistribution,
                              MultiSpectralDistributions]],
               MultiSpectralDistributions, ],
    cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[
        MultiSpectralDistributions,
        str]], ] = "CIE 1931 2 Degree Standard Observer",
    chromaticity_diagram_callable: Callable = plot_chromaticity_diagram,
    method: Union[Literal["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"],
                  str] = "CIE 1931",
    annotate_kwargs: Optional[Union[Dict, List[Dict]]] = None,
    plot_kwargs: Optional[Union[Dict, List[Dict]]] = None,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot given spectral distribution chromaticity coordinates into the
    *Chromaticity Diagram* using given method.

    Parameters
    ----------
    sds
        Spectral distributions or multi-spectral distributions to
        plot. `sds` can be a single
        :class:`colour.MultiSpectralDistributions` class instance, a list
        of :class:`colour.MultiSpectralDistributions` class instances or a
        list of :class:`colour.SpectralDistribution` class instances.
    cmfs
        Standard observer colour matching functions used for computing the
        spectral locus boundaries. ``cmfs`` can be of any type or form
        supported by the :func:`colour.plotting.filter_cmfs` definition.
    chromaticity_diagram_callable
        Callable responsible for drawing the *Chromaticity Diagram*.
    method
        *Chromaticity Diagram* method.
    annotate_kwargs
        Keyword arguments for the :func:`matplotlib.pyplot.annotate`
        definition, used to annotate the resulting chromaticity coordinates
        with their respective spectral distribution names. ``annotate_kwargs``
        can be either a single dictionary applied to all the arrows with same
        settings or a sequence of dictionaries with different settings for each
        spectral distribution. The following special keyword arguments can also
        be used:

        -   ``annotate`` : Whether to annotate the spectral distributions.
    plot_kwargs
        Keyword arguments for the :func:`matplotlib.pyplot.plot` definition,
        used to control the style of the plotted spectral distributions.
        `plot_kwargs`` can be either a single dictionary applied to all the
        plotted spectral distributions with the same settings or a sequence of
        dictionaries with different settings for each plotted spectral
        distributions. The following special keyword arguments can also be
        used:

        -   ``illuminant`` : The illuminant used to compute the spectral
            distributions colours. The default is the illuminant associated
            with the whitepoint of the default plotting colourspace.
            ``illuminant`` can be of any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   ``cmfs`` : The standard observer colour matching functions used for
            computing the spectral distributions colours. ``cmfs`` can be of
            any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   ``normalise_sd_colours`` : Whether to normalise the computed
            spectral distributions colours. The default is *True*.
        -   ``use_sd_colours`` : Whether to use the computed spectral
            distributions colours under the plotting colourspace illuminant.
            Alternatively, it is possible to use the
            :func:`matplotlib.pyplot.plot` definition ``color`` argument with
            pre-computed values. The default is *True*.

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

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

    Examples
    --------
    >>> A = SDS_ILLUMINANTS['A']
    >>> D65 = SDS_ILLUMINANTS['D65']
    >>> annotate_kwargs = [
    ...     {'xytext': (-25, 15), 'arrowprops':{'arrowstyle':'-'}},
    ...     {}
    ... ]
    >>> plot_kwargs = [
    ...     {
    ...         'illuminant': SDS_ILLUMINANTS['E'],
    ...         'markersize' : 15,
    ...         'normalise_sd_colours': True,
    ...         'use_sd_colours': True
    ...     },
    ...     {'illuminant': SDS_ILLUMINANTS['E']},
    ... ]
    >>> plot_sds_in_chromaticity_diagram(
    ...     [A, D65], annotate_kwargs=annotate_kwargs, plot_kwargs=plot_kwargs)
    ... # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_SDS_In_Chromaticity_Diagram.png
        :align: center
        :alt: plot_sds_in_chromaticity_diagram
    """

    method = validate_method(method,
                             ["CIE 1931", "CIE 1960 UCS", "CIE 1976 UCS"])

    sds_converted = sds_and_msds_to_sds(sds)

    settings: Dict[str, Any] = {"uniform": True}
    settings.update(kwargs)

    _figure, axes = artist(**settings)

    settings.update({
        "axes": axes,
        "standalone": False,
        "method": method,
        "cmfs": cmfs,
    })

    chromaticity_diagram_callable(**settings)

    if method == "cie 1931":

        def XYZ_to_ij(XYZ: NDArray) -> NDArray:
            """
            Convert given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return XYZ_to_xy(XYZ)

        bounding_box = (-0.1, 0.9, -0.1, 0.9)
    elif method == "cie 1960 ucs":

        def XYZ_to_ij(XYZ: NDArray) -> NDArray:
            """
            Convert given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return UCS_to_uv(XYZ_to_UCS(XYZ))

        bounding_box = (-0.1, 0.7, -0.2, 0.6)

    elif method == "cie 1976 ucs":

        def XYZ_to_ij(XYZ: NDArray) -> NDArray:
            """
            Convert given *CIE XYZ* tristimulus values to *ij* chromaticity
            coordinates.
            """

            return Luv_to_uv(XYZ_to_Luv(XYZ))

        bounding_box = (-0.1, 0.7, -0.1, 0.7)

    annotate_settings_collection = [{
        "annotate":
        True,
        "xytext": (-50, 30),
        "textcoords":
        "offset points",
        "arrowprops":
        CONSTANTS_ARROW_STYLE,
        "zorder":
        CONSTANTS_COLOUR_STYLE.zorder.midground_annotation,
    } for _ in range(len(sds_converted))]

    if annotate_kwargs is not None:
        update_settings_collection(annotate_settings_collection,
                                   annotate_kwargs, len(sds_converted))

    plot_settings_collection = [{
        "color":
        CONSTANTS_COLOUR_STYLE.colour.brightest,
        "label":
        f"{sd.strict_name}",
        "marker":
        "o",
        "markeredgecolor":
        CONSTANTS_COLOUR_STYLE.colour.dark,
        "markeredgewidth":
        CONSTANTS_COLOUR_STYLE.geometry.short * 0.75,
        "markersize": (CONSTANTS_COLOUR_STYLE.geometry.short * 6 +
                       CONSTANTS_COLOUR_STYLE.geometry.short * 0.75),
        "zorder":
        CONSTANTS_COLOUR_STYLE.zorder.midground_line,
        "cmfs":
        cmfs,
        "illuminant":
        SDS_ILLUMINANTS[
            CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint_name],
        "use_sd_colours":
        False,
        "normalise_sd_colours":
        False,
    } for sd in sds_converted]

    if plot_kwargs is not None:
        update_settings_collection(plot_settings_collection, plot_kwargs,
                                   len(sds_converted))

    for i, sd in enumerate(sds_converted):
        plot_settings = plot_settings_collection[i]

        cmfs = cast(
            MultiSpectralDistributions,
            first_item(filter_cmfs(plot_settings.pop("cmfs")).values()),
        )
        illuminant = cast(
            SpectralDistribution,
            first_item(
                filter_illuminants(plot_settings.pop("illuminant")).values()),
        )
        normalise_sd_colours = plot_settings.pop("normalise_sd_colours")
        use_sd_colours = plot_settings.pop("use_sd_colours")

        with domain_range_scale("1"):
            XYZ = sd_to_XYZ(sd, cmfs, illuminant)

        if use_sd_colours:
            if normalise_sd_colours:
                XYZ /= XYZ[..., 1]

            plot_settings["color"] = np.clip(XYZ_to_plotting_colourspace(XYZ),
                                             0, 1)

        ij = XYZ_to_ij(XYZ)

        axes.plot(ij[0], ij[1], **plot_settings)

        if sd.name is not None and annotate_settings_collection[i]["annotate"]:
            annotate_settings = annotate_settings_collection[i]
            annotate_settings.pop("annotate")

            axes.annotate(sd.name, xy=ij, **annotate_settings)

    settings.update({"standalone": True, "bounding_box": bounding_box})
    settings.update(kwargs)

    return render(**settings)
Ejemplo n.º 15
0
def plot_multi_sds(sds, plot_kwargs=None, **kwargs):
    """
    Plots given spectral distributions.

    Parameters
    ----------
    sds : array_like or MultiSpectralDistributions
        Spectral distributions or multi-spectral distributions to
        plot. `sds` can be a single
        :class:`colour.MultiSpectralDistributions` class instance, a list
        of :class:`colour.MultiSpectralDistributions` class instances or a
        list of :class:`colour.SpectralDistribution` class instances.
    plot_kwargs : dict or array_like, optional
        Keyword arguments for the :func:`plt.plot` definition, used to control
        the style of the plotted spectral distributions. ``plot_kwargs`` can be
        either a single dictionary applied to all the plotted spectral
        distributions with same settings or a sequence of dictionaries with
        different settings for each plotted spectral distributions.
        The following special keyword arguments can also be used:

        -   *illuminant* : unicode or :class:`colour.SpectralDistribution`, the
            illuminant used to compute the spectral distributions colours. The
            default is the illuminant associated with the whitepoint of the
            default plotting colourspace. ``illuminant`` can be of any type or
            form supported by the :func:`colour.plotting.filter_cmfs`
            definition.
        -   *cmfs* : unicode, the standard observer colour matching functions
            used for computing the spectral distributions colours. ``cmfs`` can
            be of any type or form supported by the
            :func:`colour.plotting.filter_cmfs` definition.
        -   *normalise_sd_colours* : bool, whether to normalise the computed
            spectral distributions colours. The default is *True*.
        -   *use_sd_colours* : bool, whether to use the computed spectral
            distributions colours under the plotting colourspace illuminant.
            Alternatively, it is possible to use the :func:`plt.plot`
            definition ``color`` argument with pre-computed values. The default
            is *True*.

    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.

    Examples
    --------
    >>> from colour import SpectralDistribution
    >>> 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
    ... }
    >>> sd_1 = SpectralDistribution(data_1, name='Custom 1')
    >>> sd_2 = SpectralDistribution(data_2, name='Custom 2')
    >>> plot_kwargs = [
    ...     {'use_sd_colours': True},
    ...     {'use_sd_colours': True, 'linestyle': 'dashed'},
    ... ]
    >>> plot_multi_sds([sd_1, sd_2], plot_kwargs=plot_kwargs)
    ... # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Multi_SDS.png
        :align: center
        :alt: plot_multi_sds
    """

    handle_arguments_deprecation(
        {'ArgumentRemoved': ['normalise_sd_colours', 'use_sds_colours']},
        **kwargs)

    _figure, axes = artist(**kwargs)

    sds = sds_and_msds_to_sds(sds)

    plot_settings_collection = [{
        'label':
        '{0}'.format(sd.strict_name),
        'cmfs':
        'CIE 1931 2 Degree Standard Observer',
        'illuminant':
        SDS_ILLUMINANTS[
            CONSTANTS_COLOUR_STYLE.colour.colourspace.whitepoint_name],
        'use_sd_colours':
        False,
        'normalise_sd_colours':
        False,
    } for sd in sds]

    if plot_kwargs is not None:
        update_settings_collection(plot_settings_collection, plot_kwargs,
                                   len(sds))

    x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], []
    for i, sd in enumerate(sds):
        plot_settings = plot_settings_collection[i]

        cmfs = first_item(filter_cmfs(plot_settings.pop('cmfs')).values())
        illuminant = first_item(
            filter_illuminants(plot_settings.pop('illuminant')).values())
        normalise_sd_colours = plot_settings.pop('normalise_sd_colours')
        use_sd_colours = plot_settings.pop('use_sd_colours')

        wavelengths, values = sd.wavelengths, sd.values

        shape = sd.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_sd_colours:
            with domain_range_scale('1'):
                XYZ = sd_to_XYZ(sd, cmfs, illuminant)

            if normalise_sd_colours:
                XYZ /= XYZ[..., 1]

            plot_settings['color'] = np.clip(XYZ_to_plotting_colourspace(XYZ),
                                             0, 1)

        axes.plot(wavelengths, values, **plot_settings)

    bounding_box = (min(x_limit_min), max(x_limit_max), min(y_limit_min),
                    max(y_limit_max) + max(y_limit_max) * 0.05)
    settings = {
        'axes': axes,
        'bounding_box': bounding_box,
        'legend': True,
        'x_label': 'Wavelength $\\lambda$ (nm)',
        'y_label': 'Spectral Distribution',
    }
    settings.update(kwargs)

    return render(**settings)