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"], )
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'])
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)