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