Beispiel #1
0
    def test_label_rectangles(self):
        """
        Tests :func:`colour.plotting.common.label_rectangles` definition.
        """

        figure, axes = artist()

        samples = np.linspace(0, 1, 10)

        _figure, axes = label_rectangles(
            samples, axes.bar(samples, 1), figure=figure, axes=axes)

        self.assertEqual(len(axes.texts), len(samples))
Beispiel #2
0
def plot_colour_quality_bars(
    specifications: Sequence[
        Union[
            ColourRendering_Specification_CQS,
            ColourRendering_Specification_CRI,
        ]
    ],
    labels: Boolean = True,
    hatching: Optional[Boolean] = None,
    hatching_repeat: Integer = 2,
    **kwargs: Any,
) -> Tuple[plt.Figure, plt.Axes]:
    """
    Plot the colour quality data of given illuminants or light sources colour
    quality specifications.

    Parameters
    ----------
    specifications
        Array of illuminants or light sources colour quality specifications.
    labels
        Add labels above bars.
    hatching
        Use hatching for the bars.
    hatching_repeat
        Hatching pattern repeat.

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

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

    Examples
    --------
    >>> from colour import (SDS_ILLUMINANTS,
    ...                     SDS_LIGHT_SOURCES, SpectralShape)
    >>> illuminant = SDS_ILLUMINANTS['FL2']
    >>> light_source = SDS_LIGHT_SOURCES['Kinoton 75P']
    >>> light_source = light_source.copy().align(SpectralShape(360, 830, 1))
    >>> cqs_i = colour_quality_scale(illuminant, additional_data=True)
    >>> cqs_l = colour_quality_scale(light_source, additional_data=True)
    >>> plot_colour_quality_bars([cqs_i, cqs_l])  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, <...AxesSubplot...>)

    .. image:: ../_static/Plotting_Plot_Colour_Quality_Bars.png
        :align: center
        :alt: plot_colour_quality_bars
    """

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

    _figure, axes = artist(**settings)

    bar_width = 0.5
    y_ticks_interval = 10
    count_s, count_Q_as = len(specifications), 0
    patterns = cycle(CONSTANTS_COLOUR_STYLE.hatch.patterns)
    if hatching is None:
        hatching = False if count_s == 1 else True

    for i, specification in enumerate(specifications):
        Q_a, Q_as, colorimetry_data = (
            specification.Q_a,
            specification.Q_as,
            specification.colorimetry_data,
        )

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

        x = (
            as_float_array(
                i
                + np.arange(
                    0,
                    (count_Q_as + 1) * (count_s + 1),
                    (count_s + 1),
                    dtype=DEFAULT_FLOAT_DTYPE,
                )
            )
            * bar_width
        )
        y = as_float_array(
            [Q_a]
            + [
                s[1].Q_a  # type: ignore[attr-defined]
                for s in sorted(Q_as.items(), key=lambda s: s[0])
            ]
        )

        bars = axes.bar(
            x,
            np.abs(y),
            color=RGB,
            width=bar_width,
            edgecolor=CONSTANTS_COLOUR_STYLE.colour.dark,
            label=specification.name,
            zorder=CONSTANTS_COLOUR_STYLE.zorder.background_polygon,
        )

        hatches = (
            [next(patterns) * hatching_repeat] * (count_Q_as + 1)
            if hatching
            else list(
                np.where(y < 0, next(patterns), None)  # type: ignore[call-overload]
            )
        )

        for j, bar in enumerate(bars.patches):
            bar.set_hatch(hatches[j])

        if labels:
            label_rectangles(
                [f"{y_v:.1f}" for y_v in y],
                bars,
                rotation="horizontal" if count_s == 1 else "vertical",
                offset=(
                    0 if count_s == 1 else 3 / 100 * count_s + 65 / 1000,
                    0.025,
                ),
                text_size=-5 / 7 * count_s + 12.5,
                axes=axes,
            )

    axes.axhline(
        y=100,
        color=CONSTANTS_COLOUR_STYLE.colour.dark,
        linestyle="--",
        zorder=CONSTANTS_COLOUR_STYLE.zorder.midground_line,
    )

    axes.set_xticks(
        (
            np.arange(
                0,
                (count_Q_as + 1) * (count_s + 1),
                (count_s + 1),
                dtype=DEFAULT_FLOAT_DTYPE,
            )
            - bar_width
        )
        * bar_width
        + (count_s * bar_width / 2)
    )
    axes.set_xticklabels(
        ["Qa"] + [f"Q{index + 1}" for index in range(0, count_Q_as, 1)]
    )
    axes.set_yticks(range(0, 100 + y_ticks_interval, y_ticks_interval))

    aspect = 1 / (120 / (bar_width + len(Q_as) + bar_width * 2))
    bounding_box = (
        -bar_width,
        ((count_Q_as + 1) * (count_s + 1)) / 2 - bar_width,
        0,
        120,
    )

    settings = {
        "axes": axes,
        "aspect": aspect,
        "bounding_box": bounding_box,
        "legend": hatching,
        "title": "Colour Quality",
    }
    settings.update(kwargs)

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

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

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

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

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

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

    canvas(**settings)

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

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

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

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

            y = np.abs(y)

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

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

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

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

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

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

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

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

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

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

    Examples
    --------
    >>> from colour import (ILLUMINANTS_SDS,
    ...                     LIGHT_SOURCES_SDS, SpectralShape)
    >>> illuminant = ILLUMINANTS_SDS['FL2']
    >>> light_source = LIGHT_SOURCES_SDS['Kinoton 75P']
    >>> light_source = light_source.copy().align(SpectralShape(360, 830, 1))
    >>> cqs_i = colour_quality_scale(illuminant, additional_data=True)
    >>> cqs_l = colour_quality_scale(light_source, additional_data=True)
    >>> plot_colour_quality_bars([cqs_i, cqs_l])  # doctest: +ELLIPSIS
    (<Figure size ... with 1 Axes>, \
<matplotlib.axes._subplots.AxesSubplot object at 0x...>)

    .. image:: ../_static/Plotting_Plot_Colour_Quality_Bars.png
        :align: center
        :alt: plot_colour_quality_bars
    """

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

    _figure, axes = artist(**settings)

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

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

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

        bars = axes.bar(x,
                        np.abs(y),
                        color=colours,
                        width=bar_width,
                        edgecolor=COLOUR_STYLE_CONSTANTS.colour.dark,
                        label=specification.name)

        hatches = ([next(patterns) * hatching_repeat] *
                   (count_Q_as + 1) if hatching else np.where(
                       y < 0, next(patterns), None).tolist())

        for j, bar in enumerate(bars.patches):
            bar.set_hatch(hatches[j])

        if labels:
            label_rectangles(
                ['{0:.1f}'.format(y_v) for y_v in y],
                bars,
                rotation='horizontal' if count_s == 1 else 'vertical',
                offset=(0 if count_s == 1 else 3 / 100 * count_s + 65 / 1000,
                        0.025),
                text_size=-5 / 7 * count_s + 12.5,
                axes=axes)

    axes.axhline(y=100,
                 color=COLOUR_STYLE_CONSTANTS.colour.dark,
                 linestyle='--')

    axes.set_xticks(
        (np.arange(0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
                   dtype=DEFAULT_FLOAT_DTYPE) * bar_width +
         (count_s * bar_width / 2)), ['Qa'] +
        ['Q{0}'.format(index + 1) for index in range(0, count_Q_as + 1, 1)])
    axes.set_yticks(range(0, 100 + y_ticks_interval, y_ticks_interval))

    aspect = 1 / (120 / (bar_width + len(Q_as) + bar_width * 2))
    bounding_box = (-bar_width, ((count_Q_as + 1) * (count_s + 1)) / 2, 0, 120)

    settings = {
        'axes': axes,
        'aspect': aspect,
        'bounding_box': bounding_box,
        'legend': hatching,
        'title': 'Colour Quality',
    }
    settings.update(kwargs)

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

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

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

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

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

    canvas(**settings)

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

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

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

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

            y = np.abs(y)

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

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

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

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

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

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

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

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

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

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

    Examples
    --------
    >>> from colour import (ILLUMINANTS_SDS,
    ...                     LIGHT_SOURCES_SDS, SpectralShape)
    >>> illuminant = ILLUMINANTS_SDS['FL2']
    >>> light_source = LIGHT_SOURCES_SDS['Kinoton 75P']
    >>> light_source = light_source.copy().align(SpectralShape(360, 830, 1))
    >>> cqs_i = colour_quality_scale(illuminant, additional_data=True)
    >>> cqs_l = colour_quality_scale(light_source, additional_data=True)
    >>> plot_colour_quality_bars([cqs_i, cqs_l])  # doctest: +SKIP

    .. image:: ../_static/Plotting_Plot_Colour_Quality_Bars.png
        :align: center
        :alt: plot_colour_quality_bars
    """

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

    _figure, axes = artist(**settings)

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

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

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

        bars = plt.bar(
            x,
            np.abs(y),
            color=colours,
            width=bar_width,
            edgecolor=COLOUR_STYLE_CONSTANTS.colour.dark,
            label=specification.name)

        hatches = ([next(patterns) * hatching_repeat] * (count_Q_as + 1)
                   if hatching else np.where(y < 0, next(patterns),
                                             None).tolist())

        for j, bar in enumerate(bars.patches):
            bar.set_hatch(hatches[j])

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

    axes.axhline(
        y=100, color=COLOUR_STYLE_CONSTANTS.colour.dark, linestyle='--')

    axes.set_xticks((np.arange(
        0, (count_Q_as + 1) * (count_s + 1), (count_s + 1),
        dtype=DEFAULT_FLOAT_DTYPE) * bar_width + (count_s * bar_width / 2)),
                    ['Qa'] + [
                        'Q{0}'.format(index + 1)
                        for index in range(0, count_Q_as + 1, 1)
                    ])
    axes.set_yticks(range(0, 100 + y_ticks_interval, y_ticks_interval))

    aspect = 1 / (120 / (bar_width + len(Q_as) + bar_width * 2))
    bounding_box = (-bar_width, ((count_Q_as + 1) * (count_s + 1)) / 2, 0, 120)

    settings = {
        'axes': axes,
        'aspect': aspect,
        'bounding_box': bounding_box,
        'legend': hatching,
        'title': 'Colour Quality',
    }
    settings.update(kwargs)

    return render(**settings)