def plot_multi_cctfs(cctfs=None, decoding_cctf=False, **kwargs): """ Plots given colour component transfer functions. Parameters ---------- cctfs : array_like, optional Colour component transfer function to plot. decoding_cctf : bool Plot the decoding colour component transfer function instead. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_cctfs(['ITU-R BT.709', 'sRGB']) # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_CCTFs.png :align: center :alt: plot_multi_cctfs """ if cctfs is None: cctfs = ('ITU-R BT.709', 'sRGB') cctfs = filter_passthrough( DECODING_CCTFS if decoding_cctf else ENCODING_CCTFS, cctfs) mode = 'Decoding' if decoding_cctf else 'Encoding' title = '{0} - {1} CCTFs'.format(', '.join([cctf for cctf in cctfs]), mode) settings = { 'bounding_box': (0, 1, 0, 1), 'legend': True, 'title': title, 'x_label': 'Signal Value' if decoding_cctf else 'Tristimulus Value', 'y_label': 'Tristimulus Value' if decoding_cctf else 'Signal Value', } settings.update(kwargs) with domain_range_scale(1): return plot_multi_functions(cctfs, **settings)
def plot_multi_munsell_value_functions( functions: Union[Callable, str, Sequence[Union[Callable, str]]], **kwargs: Any, ) -> Tuple[plt.Figure, plt.Axes]: """ Plot given *Munsell* value functions. Parameters ---------- functions *Munsell* value functions to plot. ``functions`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` definition. Other Parameters ---------------- kwargs {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> plot_multi_munsell_value_functions(['ASTM D1535', 'McCamy 1987']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_Multi_Munsell_Value_Functions.png :align: center :alt: plot_multi_munsell_value_functions """ functions_filtered = filter_passthrough(MUNSELL_VALUE_METHODS, functions) settings: Dict[str, Any] = { "bounding_box": (0, 100, 0, 10), "legend": True, "title": f"{', '.join(functions_filtered)} - Munsell Functions", "x_label": "Luminance Y", "y_label": "Munsell Value V", } settings.update(kwargs) return plot_multi_functions(functions_filtered, samples=np.linspace(0, 100, 1000), **settings)
def plot_multi_luminance_functions( functions: Union[Callable, str, Sequence[Union[Callable, str]]], **kwargs: Any, ) -> Tuple[plt.Figure, plt.Axes]: """ Plot given *Luminance* functions. Parameters ---------- functions *Luminance* functions to plot. ``functions`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` definition. Other Parameters ---------------- kwargs {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> plot_multi_luminance_functions(['CIE 1976', 'Newhall 1943']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_Multi_Luminance_Functions.png :align: center :alt: plot_multi_luminance_functions """ functions_filtered = filter_passthrough(LUMINANCE_METHODS, functions) settings: Dict[str, Any] = { "bounding_box": (0, 1, 0, 1), "legend": True, "title": f"{', '.join(functions_filtered)} - Luminance Functions", "x_label": "Normalised Munsell Value / Lightness", "y_label": "Normalised Relative Luminance Y", } settings.update(kwargs) with domain_range_scale("1"): return plot_multi_functions(functions_filtered, **settings)
def plot_multi_munsell_value_functions(functions=None, **kwargs): """ Plots given *Munsell* value functions. Parameters ---------- functions : array_like, optional *Munsell* value functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_munsell_value_functions(['ASTM D1535', 'McCamy 1987']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Multi_Munsell_Value_Functions.png :align: center :alt: plot_multi_munsell_value_functions """ if functions is None: functions = ('ASTM D1535', 'McCamy 1987') functions = filter_passthrough(MUNSELL_VALUE_METHODS, functions) settings = { 'bounding_box': (0, 100, 0, 10), 'legend': True, 'title': '{0} - Munsell Functions'.format(', '.join(functions)), 'x_label': 'Luminance Y', 'y_label': 'Munsell Value V', } settings.update(kwargs) return plot_multi_functions(functions, samples=np.linspace(0, 100, 1000), **settings)
def plot_multi_luminance_functions(functions=None, **kwargs): """ Plots given *Luminance* functions. Parameters ---------- functions : array_like, optional *Luminance* functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_luminance_functions(['CIE 1976', 'Newhall 1943']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Multi_Luminance_Functions.png :align: center :alt: plot_multi_luminance_functions """ if functions is None: functions = ('CIE 1976', 'Newhall 1943') functions = filter_passthrough(LUMINANCE_METHODS, functions) settings = { 'bounding_box': (0, 1, 0, 1), 'legend': True, 'title': '{0} - Luminance Functions'.format(', '.join(functions)), 'x_label': 'Normalised Munsell Value / Lightness', 'y_label': 'Normalised Relative Luminance Y', } settings.update(kwargs) with domain_range_scale(1): return plot_multi_functions(functions, **settings)
def plot_multi_luminance_functions(functions=None, **kwargs): """ Plots given *Luminance* functions. Parameters ---------- functions : array_like, optional *Luminance* functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_luminance_functions(['CIE 1976', 'Newhall 1943']) ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_Luminance_Functions.png :align: center :alt: plot_multi_luminance_functions """ if functions is None: functions = ('CIE 1976', 'Newhall 1943') functions = filter_passthrough(LUMINANCE_METHODS, functions) settings = { 'bounding_box': (0, 1, 0, 1), 'legend': True, 'title': '{0} - Luminance Functions'.format(', '.join(functions)), 'x_label': 'Normalised Munsell Value / Lightness', 'y_label': 'Normalised Relative Luminance Y', } settings.update(kwargs) with domain_range_scale(1): return plot_multi_functions(functions, **settings)
def plot_multi_lightness_functions(functions=None, **kwargs): """ Plots given *Lightness* functions. Parameters ---------- functions : array_like, optional *Lightness* functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_lightness_functions(['CIE 1976', 'Wyszecki 1963']) ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_Lightness_Functions.png :align: center :alt: plot_multi_lightness_functions """ if functions is None: functions = ('CIE 1976', 'Wyszecki 1963') functions = filter_passthrough(LIGHTNESS_METHODS, functions) settings = { 'bounding_box': (0, 1, 0, 1), 'legend': True, 'title': '{0} - Lightness Functions'.format(', '.join(functions)), 'x_label': 'Normalised Relative Luminance Y', 'y_label': 'Normalised Lightness', } settings.update(kwargs) with domain_range_scale(1): return plot_multi_functions(functions, **settings)
def plot_multi_munsell_value_functions(functions=None, **kwargs): """ Plots given *Munsell* value functions. Parameters ---------- functions : array_like, optional *Munsell* value functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_munsell_value_functions(['ASTM D1535-08', 'McCamy 1987']) ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_Munsell_Value_Functions.png :align: center :alt: plot_multi_munsell_value_functions """ if functions is None: functions = ('ASTM D1535-08', 'McCamy 1987') functions = filter_passthrough(MUNSELL_VALUE_METHODS, functions) settings = { 'bounding_box': (0, 100, 0, 10), 'legend': True, 'title': '{0} - Munsell Functions'.format(', '.join(functions)), 'x_label': 'Luminance Y', 'y_label': 'Munsell Value V', } settings.update(kwargs) return plot_multi_functions( functions, samples=np.linspace(0, 100, 1000), **settings)
def plot_multi_lightness_functions(functions, **kwargs): """ Plots given *Lightness* functions. Parameters ---------- functions : unicode or object or array_like *Lightness* functions to plot. ``functions`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` definition. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_functions`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_multi_lightness_functions(['CIE 1976', 'Wyszecki 1963']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_Multi_Lightness_Functions.png :align: center :alt: plot_multi_lightness_functions """ functions = filter_passthrough(LIGHTNESS_METHODS, functions) settings = { 'bounding_box': (0, 1, 0, 1), 'legend': True, 'title': '{0} - Lightness Functions'.format(', '.join(functions)), 'x_label': 'Normalised Relative Luminance Y', 'y_label': 'Normalised Lightness', } settings.update(kwargs) with domain_range_scale(1): return plot_multi_functions(functions, **settings)
def test_filter_passthrough(self): """Test :func:`colour.plotting.common.filter_passthrough` definition.""" self.assertListEqual( sorted(colourspace.name for colourspace in filter_passthrough( RGB_COLOURSPACES, ["^ACES.*"]).values()), ["ACES2065-1", "ACEScc", "ACEScct", "ACEScg", "ACESproxy"], ) self.assertListEqual( sorted(filter_passthrough(RGB_COLOURSPACES, ["^ACEScc$"]).keys()), ["ACEScc"], ) self.assertListEqual( sorted(filter_passthrough(RGB_COLOURSPACES, ["^acescc$"]).keys()), ["ACEScc"], ) self.assertDictEqual( filter_passthrough( SDS_ILLUMINANTS, [SDS_ILLUMINANTS["D65"], { "Is": "Excluded" }], allow_non_siblings=False, ), {"D65": SDS_ILLUMINANTS["D65"]}, ) self.assertDictEqual( filter_passthrough( SDS_ILLUMINANTS, [SDS_ILLUMINANTS["D65"], { "Is": "Included" }], allow_non_siblings=True, ), { "D65": SDS_ILLUMINANTS["D65"], "Is": "Included" }, ) self.assertListEqual( sorted(element for element in filter_passthrough( { "John": "Doe", "Luke": "Skywalker" }, ["John"]).values()), ["Doe", "John"], )
def test_filter_passthrough(self): """ Tests :func:`colour.plotting.common.filter_passthrough` definition. """ self.assertListEqual( sorted([ colourspace.name for colourspace in filter_passthrough( RGB_COLOURSPACES, ['^ACES.*']).values() ]), ['ACES2065-1', 'ACEScc', 'ACEScct', 'ACEScg', 'ACESproxy']) self.assertListEqual( sorted(filter_passthrough(RGB_COLOURSPACES, ['^ACEScc$']).keys()), ['ACEScc']) self.assertListEqual( sorted(filter_passthrough(RGB_COLOURSPACES, ['^acescc$']).keys()), ['ACEScc']) self.assertDictEqual( filter_passthrough(SDS_ILLUMINANTS, [SDS_ILLUMINANTS['D65'], { 'Is': 'Excluded' }], allow_non_siblings=False), {'D65': SDS_ILLUMINANTS['D65']}) self.assertDictEqual( filter_passthrough(SDS_ILLUMINANTS, [SDS_ILLUMINANTS['D65'], { 'Is': 'Included' }], allow_non_siblings=True), { 'D65': SDS_ILLUMINANTS['D65'], 'Is': 'Included' }) self.assertListEqual( sorted([ element for element in filter_passthrough( { 'John': 'Doe', 'Luke': 'Skywalker' }, ['John']).values() ]), ['Doe', 'John'])
def plot_planckian_locus_in_chromaticity_diagram( illuminants=None, annotate_parameters=None, chromaticity_diagram_callable=plot_chromaticity_diagram, planckian_locus_callable=plot_planckian_locus, method='CIE 1931', **kwargs): """ Plots the *Planckian Locus* and given illuminants in the *Chromaticity Diagram* according to given method. Parameters ---------- illuminants : array_like, optional Factory illuminants to plot. annotate_parameters : dict or array_like, optional Parameters for the :func:`plt.annotate` definition, used to annotate the resulting chromaticity coordinates with their respective illuminant names if ``annotate`` is set to *True*. ``annotate_parameters`` can be either a single dictionary applied to all the arrows with same settings or a sequence of dictionaries with different settings for each illuminant. chromaticity_diagram_callable : callable, optional Callable responsible for drawing the *Chromaticity Diagram*. planckian_locus_callable : callable, optional Callable responsible for drawing the *Planckian Locus*. method : unicode, optional **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**, *Chromaticity Diagram* method. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.temperature.plot_planckian_locus`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_planckian_locus_in_chromaticity_diagram(['A', 'B', 'C']) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_\ Plot_Planckian_Locus_In_Chromaticity_Diagram.png :align: center :alt: plot_planckian_locus_in_chromaticity_diagram """ cmfs = CMFS['CIE 1931 2 Degree Standard Observer'] if illuminants is None: illuminants = ('A', 'B', 'C') illuminants = filter_passthrough(ILLUMINANTS.get(cmfs.name), illuminants) settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False chromaticity_diagram_callable(**settings) planckian_locus_callable(**settings) if method == 'CIE 1931': def xy_to_ij(xy): """ Converts given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy bounding_box = (-0.1, 0.9, -0.1, 0.9) elif method == 'CIE 1960 UCS': def xy_to_ij(xy): """ Converts given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) bounding_box = (-0.1, 0.7, -0.2, 0.6) else: raise ValueError('Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\'}}'.format(method)) annotate_settings_collection = [{ 'annotate': True, 'xytext': (-50, 30), 'textcoords': 'offset points', 'arrowprops': COLOUR_ARROW_STYLE, } for _ in range(len(illuminants))] if annotate_parameters is not None: if not isinstance(annotate_parameters, dict): assert len(annotate_parameters) == len(illuminants), ( 'Multiple annotate parameters defined, but they do not match ' 'the illuminants count!') for i, annotate_settings in enumerate(annotate_settings_collection): if isinstance(annotate_parameters, dict): annotate_settings.update(annotate_parameters) else: annotate_settings.update(annotate_parameters[i]) for i, (illuminant, xy) in enumerate(illuminants.items()): ij = xy_to_ij(xy) axes.plot(ij[0], ij[1], 'o', color=COLOUR_STYLE_CONSTANTS.colour.brightest, markeredgecolor=COLOUR_STYLE_CONSTANTS.colour.dark, markersize=(COLOUR_STYLE_CONSTANTS.geometry.short * 6 + COLOUR_STYLE_CONSTANTS.geometry.short * 0.75), markeredgewidth=COLOUR_STYLE_CONSTANTS.geometry.short * 0.75, label=illuminant) if annotate_settings_collection[i]['annotate']: annotate_settings = annotate_settings_collection[i] annotate_settings.pop('annotate') axes.annotate(illuminant, xy=ij, **annotate_settings) title = (('{0} Illuminants - Planckian Locus\n' '{1} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer').format( ', '.join(illuminants), method) if illuminants else ('Planckian Locus\n{0} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer'.format(method))) settings.update({ 'axes': axes, 'standalone': True, 'bounding_box': bounding_box, 'title': title, }) settings.update(kwargs) return render(**settings)
def plot_planckian_locus_in_chromaticity_diagram( illuminants: Union[str, Sequence[str]], chromaticity_diagram_callable: Callable = ( plot_chromaticity_diagram # type: ignore[has-type] ), method: Union[Literal["CIE 1931", "CIE 1960 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 the *Planckian Locus* and given illuminants in the *Chromaticity Diagram* according to given method. Parameters ---------- illuminants Illuminants to plot. ``illuminants`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` 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 illuminants. ``plot_kwargs`` can be either a single dictionary applied to all the plotted illuminants with the same settings or a sequence of dictionaries with different settings for eachplotted illuminant. Other Parameters ---------------- kwargs {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.temperature.plot_planckian_locus`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> annotate_kwargs = [ ... {'xytext': (-25, 15), 'arrowprops':{'arrowstyle':'-'}}, ... {'arrowprops':{'arrowstyle':'-['}}, ... {}, ... ] >>> plot_kwargs = [ ... { ... 'markersize' : 15, ... }, ... { 'color': 'r'}, ... {}, ... ] >>> plot_planckian_locus_in_chromaticity_diagram( ... ['A', 'B', 'C'], ... annotate_kwargs=annotate_kwargs, ... plot_kwargs=plot_kwargs ... ) # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_\ Plot_Planckian_Locus_In_Chromaticity_Diagram.png :align: center :alt: plot_planckian_locus_in_chromaticity_diagram """ cmfs = MSDS_CMFS["CIE 1931 2 Degree Standard Observer"] illuminants_filtered = filter_passthrough( CCS_ILLUMINANTS.get(cmfs.name), illuminants # type: ignore[arg-type] ) settings: Dict[str, Any] = {"uniform": True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() settings = {"axes": axes, "method": method} settings.update(kwargs) settings["standalone"] = False chromaticity_diagram_callable(**settings) plot_planckian_locus(**settings) if method == "CIE 1931": def xy_to_ij(xy: NDArray) -> NDArray: """ Convert given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy bounding_box = (-0.1, 0.9, -0.1, 0.9) elif method == "CIE 1960 UCS": def xy_to_ij(xy: NDArray) -> NDArray: """ Convert given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) bounding_box = (-0.1, 0.7, -0.2, 0.6) else: raise ValueError(f'Invalid method: "{method}", must be one of ' f'["CIE 1931", "CIE 1960 UCS"]') annotate_settings_collection = [{ "annotate": True, "xytext": (-50, 30), "textcoords": "offset points", "arrowprops": CONSTANTS_ARROW_STYLE, "zorder": CONSTANTS_COLOUR_STYLE.zorder.foreground_annotation, } for _ in range(len(illuminants_filtered))] if annotate_kwargs is not None: update_settings_collection( annotate_settings_collection, annotate_kwargs, len(illuminants_filtered), ) plot_settings_collection = [{ "color": CONSTANTS_COLOUR_STYLE.colour.brightest, "label": f"{illuminant}", "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.foreground_line, } for illuminant in illuminants_filtered] if plot_kwargs is not None: update_settings_collection(plot_settings_collection, plot_kwargs, len(illuminants_filtered)) for i, (illuminant, xy) in enumerate(illuminants_filtered.items()): plot_settings = plot_settings_collection[i] ij = xy_to_ij(xy) axes.plot(ij[0], ij[1], **plot_settings) if annotate_settings_collection[i]["annotate"]: annotate_settings = annotate_settings_collection[i] annotate_settings.pop("annotate") axes.annotate(illuminant, xy=ij, **annotate_settings) title = (( f"{', '.join(illuminants_filtered)} Illuminants - Planckian Locus\n" f"{method.upper()} Chromaticity Diagram - " "CIE 1931 2 Degree Standard Observer") if illuminants_filtered else (f"Planckian Locus\n{method.upper()} Chromaticity Diagram - " f"CIE 1931 2 Degree Standard Observer")) settings.update({ "axes": axes, "standalone": True, "bounding_box": bounding_box, "title": title, }) settings.update(kwargs) return render(**settings)
def plot_planckian_locus_in_chromaticity_diagram( illuminants, chromaticity_diagram_callable=plot_chromaticity_diagram, planckian_locus_callable=plot_planckian_locus, method='CIE 1931', annotate_kwargs=None, plot_kwargs=None, **kwargs): """ Plots the *Planckian Locus* and given illuminants in the *Chromaticity Diagram* according to given method. Parameters ---------- illuminants : unicode or object or array_like Illuminants to plot. ``illuminants`` elements can be of any type or form supported by the :func:`colour.plotting.filter_passthrough` definition. chromaticity_diagram_callable : callable, optional Callable responsible for drawing the *Chromaticity Diagram*. planckian_locus_callable : callable, optional Callable responsible for drawing the *Planckian Locus*. 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 illuminant 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 illuminant. The following special keyword arguments can also be used: - *annotate* : bool, whether to annotate the illuminants. plot_kwargs : dict or array_like, optional Keyword arguments for the :func:`plt.plot` definition, used to control the style of the plotted illuminants. ``plot_kwargs`` can be either a single dictionary applied to all the plotted illuminants with same settings or a sequence of dictionaries with different settings for each plotted illuminant. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.temperature.plot_planckian_locus`, :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 -------- >>> annotate_kwargs = [ ... {'xytext': (-25, 15), 'arrowprops':{'arrowstyle':'-'}}, ... {'arrowprops':{'arrowstyle':'-['}}, ... {}, ... ] >>> plot_kwargs = [ ... { ... 'markersize' : 15, ... }, ... { 'color': 'r'}, ... {}, ... ] >>> plot_planckian_locus_in_chromaticity_diagram( ... ['A', 'B', 'C'], ... annotate_kwargs=annotate_kwargs, ... plot_kwargs=plot_kwargs ... ) # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_\ Plot_Planckian_Locus_In_Chromaticity_Diagram.png :align: center :alt: plot_planckian_locus_in_chromaticity_diagram """ annotate_kwargs = handle_arguments_deprecation( { 'ArgumentRenamed': [['annotate_parameters', 'annotate_kwargs']], }, **kwargs).get('annotate_kwargs', annotate_kwargs) cmfs = MSDS_CMFS['CIE 1931 2 Degree Standard Observer'] illuminants = filter_passthrough(CCS_ILLUMINANTS.get(cmfs.name), illuminants) settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False chromaticity_diagram_callable(**settings) planckian_locus_callable(**settings) if method == 'CIE 1931': def xy_to_ij(xy): """ Converts given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy bounding_box = (-0.1, 0.9, -0.1, 0.9) elif method == 'CIE 1960 UCS': def xy_to_ij(xy): """ Converts given *CIE xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) bounding_box = (-0.1, 0.7, -0.2, 0.6) else: raise ValueError('Invalid method: "{0}", must be one of ' '[\'CIE 1931\', \'CIE 1960 UCS\']'.format(method)) annotate_settings_collection = [{ 'annotate': True, 'xytext': (-50, 30), 'textcoords': 'offset points', 'arrowprops': CONSTANTS_ARROW_STYLE, } for _ in range(len(illuminants))] if annotate_kwargs is not None: update_settings_collection(annotate_settings_collection, annotate_kwargs, len(illuminants)) plot_settings_collection = [{ 'color': CONSTANTS_COLOUR_STYLE.colour.brightest, 'label': '{0}'.format(illuminant), '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), } for illuminant in illuminants] if plot_kwargs is not None: update_settings_collection(plot_settings_collection, plot_kwargs, len(illuminants)) for i, (illuminant, xy) in enumerate(illuminants.items()): plot_settings = plot_settings_collection[i] ij = xy_to_ij(xy) axes.plot(ij[0], ij[1], **plot_settings) if annotate_settings_collection[i]['annotate']: annotate_settings = annotate_settings_collection[i] annotate_settings.pop('annotate') axes.annotate(illuminant, xy=ij, **annotate_settings) title = (('{0} Illuminants - Planckian Locus\n' '{1} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer').format( ', '.join(illuminants), method) if illuminants else ('Planckian Locus\n{0} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer'.format(method))) settings.update({ 'axes': axes, 'standalone': True, 'bounding_box': bounding_box, 'title': title, }) settings.update(kwargs) return render(**settings)
def plot_planckian_locus_in_chromaticity_diagram( illuminants=None, annotate_parameters=None, chromaticity_diagram_callable=plot_chromaticity_diagram, method='CIE 1931', **kwargs): """ Plots the *Planckian Locus* and given illuminants in the *Chromaticity Diagram* according to given method. Parameters ---------- illuminants : array_like, optional Factory illuminants to plot. annotate_parameters : dict or array_like, optional Parameters for the :func:`plt.annotate` definition, used to annotate the resulting chromaticity coordinates with their respective illuminant names if ``annotate`` is set to *True*. ``annotate_parameters`` can be either a single dictionary applied to all the arrows with same settings or a sequence of dictionaries with different settings for each illuminant. 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. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.temperature.plot_planckian_locus`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_planckian_locus_in_chromaticity_diagram(['A', 'B', 'C']) ... # doctest: +SKIP .. image:: ../_static/Plotting_\ Plot_Planckian_Locus_In_Chromaticity_Diagram.png :align: center :alt: plot_planckian_locus_in_chromaticity_diagram """ cmfs = CMFS['CIE 1931 2 Degree Standard Observer'] if illuminants is None: illuminants = ('A', 'B', 'C') illuminants = filter_passthrough(ILLUMINANTS.get(cmfs.name), illuminants) settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False chromaticity_diagram_callable(**settings) plot_planckian_locus(**settings) if method == 'CIE 1931': def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy bounding_box = (-0.1, 0.9, -0.1, 0.9) elif method == 'CIE 1960 UCS': def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return UCS_to_uv(XYZ_to_UCS(xy_to_XYZ(xy))) bounding_box = (-0.1, 0.7, -0.2, 0.6) else: raise ValueError('Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\'}}'.format(method)) annotate_settings_collection = [{ 'annotate': True, 'xytext': (-50, 30), 'textcoords': 'offset points', 'arrowprops': COLOUR_ARROW_STYLE, } for _ in range(len(illuminants))] if annotate_parameters is not None: if not isinstance(annotate_parameters, dict): assert len(annotate_parameters) == len(illuminants), ( 'Multiple annotate parameters defined, but they do not match ' 'the illuminants count!') for i, annotate_settings in enumerate(annotate_settings_collection): if isinstance(annotate_parameters, dict): annotate_settings.update(annotate_parameters) else: annotate_settings.update(annotate_parameters[i]) for i, (illuminant, xy) in enumerate(illuminants.items()): ij = xy_to_ij(xy) axes.plot( ij[0], ij[1], 'o', color=COLOUR_STYLE_CONSTANTS.colour.brightest, markeredgecolor=COLOUR_STYLE_CONSTANTS.colour.dark, markersize=(COLOUR_STYLE_CONSTANTS.geometry.short * 6 + COLOUR_STYLE_CONSTANTS.geometry.short * 0.75), markeredgewidth=COLOUR_STYLE_CONSTANTS.geometry.short * 0.75, label=illuminant) if annotate_settings_collection[i]['annotate']: annotate_settings = annotate_settings_collection[i] annotate_settings.pop('annotate') plt.annotate(illuminant, xy=ij, **annotate_settings) title = (('{0} Illuminants - Planckian Locus\n' '{1} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer').format( ', '.join(illuminants), method) if illuminants else ('Planckian Locus\n{0} Chromaticity Diagram - ' 'CIE 1931 2 Degree Standard Observer'.format(method))) settings.update({ 'axes': axes, 'standalone': True, 'bounding_box': bounding_box, 'title': title, }) settings.update(kwargs) return render(**settings)