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 test_first_item(self): """ Tests :func:`colour.utilities.common.first_item` definition. """ self.assertEqual(first_item(range(10)), 0) dictionary = OrderedDict([(0, 'a'), (1, 'b'), (2, 'c')]) self.assertEqual(first_item(dictionary.items()), (0, 'a')) self.assertEqual(first_item(dictionary.values()), 'a')
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 __contains__(self, x): """ Returns whether the multi-continuous signal contains given independent domain :math:`x` variable. Parameters ---------- x : numeric, array_like or slice Independent domain :math:`x` variable. Returns ------- bool Is :math:`x` domain value contained. Examples -------- >>> range_ = np.linspace(10, 100, 10) >>> multi_signal = MultiSignal(range_) >>> 0 in multi_signal True >>> 0.5 in multi_signal True >>> 1000 in multi_signal False """ if self._signals: return x in first_item(self._signals.values()) else: raise RuntimeError('No underlying "Signal" defined!')
def chromaticity_diagram_construction_visual( cmfs='CIE 1931 2 Degree Standard Observer', width=2.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Node` class instance representing the chromaticity diagram construction with the spectral locus. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. width : numeric, optional Line width. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Node Chromaticity diagram construction visual. """ from colour_analysis.visuals import Primitive node = Node(parent=parent) simplex_p = np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]) simplex_f = np.array([(0, 1, 2)]) simplex_c = np.array([(1, 1, 1), (1, 1, 1), (1, 1, 1)]) Primitive(simplex_p, simplex_f, uniform_opacity=0.5, vertex_colours=simplex_c, parent=node) simplex_f = np.array([(0, 1, 2), (1, 2, 0), (2, 0, 1)]) Primitive(simplex_p, simplex_f, uniform_opacity=1.0, vertex_colours=simplex_c, wireframe=True, parent=node) lines = [] for XYZ in first_item(filter_cmfs(cmfs).values()).values: lines.append(XYZ * 1.75) lines.append((0, 0, 0)) lines = np.array(lines) Line(lines, (0, 0, 0), width=width, method=method, parent=node) return node
def spectral_locus_visual(colourspace=PRIMARY_COLOURSPACE, colourspace_model=COLOURSPACE_MODEL, cmfs='CIE 1931 2 Degree Standard Observer'): """ Returns the spectral locus visual geometry formatted as *JSON*. Parameters ---------- colourspace : unicode, optional RGB colourspace used to generate the visual geometry. colourspace_model : unicode, optional Colourspace model used to generate the visual geometry. cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. Returns ------- unicode Spectral locus visual geometry formatted as *JSON*. """ colourspace = first_item( filter_RGB_colourspaces(re.escape(colourspace)).values()) cmfs = first_item(filter_cmfs(cmfs).values()) XYZ = cmfs.values XYZ = np.vstack([XYZ, XYZ[0, ...]]) vertices = colourspace_model_axis_reorder( XYZ_to_colourspace_model( XYZ, colourspace.whitepoint, colourspace_model, ), colourspace_model) RGB = normalise_maximum(XYZ_to_RGB( XYZ, colourspace.whitepoint, colourspace.whitepoint, colourspace.matrix_XYZ_to_RGB, ), axis=-1) return buffer_geometry(position=vertices, color=RGB)
def chromaticity_diagram_visual(samples=256, cmfs='CIE 1931 2 Degree Standard Observer', transformation='CIE 1931', parent=None): """ Creates a chromaticity diagram visual based on :class:`colour_analysis.visuals.Primitive` class. Parameters ---------- samples : int, optional Inner samples count used to construct the chromaticity diagram triangulation. cmfs : unicode, optional Standard observer colour matching functions used for the chromaticity diagram boundaries. transformation : unicode, optional **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**, Chromaticity diagram transformation. parent : Node, optional Parent of the chromaticity diagram in the `SceneGraph`. Returns ------- Primitive Chromaticity diagram visual. """ cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = DEFAULT_PLOTTING_ILLUMINANT XYZ_to_ij = ( CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['XYZ_to_ij']) ij_to_XYZ = ( CHROMATICITY_DIAGRAM_TRANSFORMATIONS[transformation]['ij_to_XYZ']) ij_c = XYZ_to_ij(cmfs.values, illuminant) triangulation = Delaunay(ij_c, qhull_options='QJ') samples = np.linspace(0, 1, samples) ii, jj = np.meshgrid(samples, samples) ij = tstack([ii, jj]) ij = np.vstack([ij_c, ij[triangulation.find_simplex(ij) > 0]]) ij_p = np.hstack([ij, np.full((ij.shape[0], 1), 0, DEFAULT_FLOAT_DTYPE)]) triangulation = Delaunay(ij, qhull_options='QJ') RGB = normalise_maximum( XYZ_to_sRGB(ij_to_XYZ(ij, illuminant), illuminant), axis=-1) diagram = Primitive( vertices=ij_p, faces=triangulation.simplices, vertex_colours=RGB, parent=parent) return diagram
def RGB_colourspace_volume_visual(colourspace=PRIMARY_COLOURSPACE, colourspace_model=COLOURSPACE_MODEL, segments=16, wireframe=False): """ Returns a RGB colourspace volume visual geometry formatted as *JSON*. Parameters ---------- colourspace : unicode, optional RGB colourspace used to generate the visual geometry. colourspace_model : unicode, optional Colourspace model used to generate the visual geometry. segments : int, optional Segments count per side of the *box* used to generate the visual geometry. wireframe : bool, optional Whether the visual geometry must represent a wireframe visual. Returns ------- unicode RGB colourspace volume visual geometry formatted as *JSON*. """ colourspace = first_item( filter_RGB_colourspaces(re.escape(colourspace)).values()) cube = conform_primitive_dtype( primitive_cube(width_segments=segments, height_segments=segments, depth_segments=segments)) vertices = cube[0]['position'] + 0.5 faces = colourspace_model_faces_reorder(np.reshape(cube[1], (-1, 1)), colourspace_model) RGB = cube[0]['colour'] XYZ = RGB_to_XYZ( vertices, colourspace.whitepoint, colourspace.whitepoint, colourspace.matrix_RGB_to_XYZ, ) vertices = colourspace_model_axis_reorder( XYZ_to_colourspace_model( XYZ, colourspace.whitepoint, colourspace_model, ), colourspace_model) return buffer_geometry(position=vertices, color=RGB, index=faces)
def RGB_colourspace_triangle_visual(colourspace='ITU-R BT.709', diagram='CIE 1931', uniform_colour=None, uniform_opacity=1.0, width=4.0, parent=None): """ Returns a :class:`vispy.scene.visuals.Line` class instance representing a *RGB* colourspace triangle visual. Parameters ---------- colourspace : unicode, optional See :func:`RGB_colourspace_volume_visual` argument for possible values. :class:`colour.RGB_Colourspace` class instance name defining the *RGB* colourspace triangle to draw. diagram : unicode, optional **{'CIE 1931', 'CIE 1960 UCS', 'CIE 1976 UCS'}**, Chromaticity diagram to use. uniform_colour : array_like, optional Uniform triangle colour. uniform_opacity : numeric, optional Uniform mesh opacity. width : numeric, optional Triangle edge width. parent : Node, optional Parent of the *RGB* colourspace volume visual in the `SceneGraph`. """ if uniform_colour is None: uniform_colour = (0.8, 0.8, 0.8) colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) illuminant = DEFAULT_PLOTTING_ILLUMINANT XYZ_to_ij = CHROMATICITY_DIAGRAM_TRANSFORMATIONS[diagram]['XYZ_to_ij'] ij = XYZ_to_ij(xy_to_XYZ(colourspace.primaries), illuminant) # TODO: Remove following hack dealing with 'agg' method issues. ij = np.vstack([ij[-1, ...], ij, ij[0, ...]]) ij[np.isnan(ij)] = 0 RGB = np.hstack([uniform_colour, uniform_opacity]) line = Line(ij, RGB, width=width, method='agg', parent=parent) return line
def add_rainbow(axis, wavelengths, values, opacity=100): # sanity check: if not hasattr(axis, 'plot') and not hasattr(axis, 'add_patch'): raise Exception("ERROR:\tFirst argument needs to have method \"plot\".") from colour.plotting import XYZ_to_plotting_colourspace, filter_cmfs, CONSTANTS_COLOUR_STYLE from colour.colorimetry import CCS_ILLUMINANTS, wavelength_to_XYZ from colour.utilities import first_item, normalise_maximum from matplotlib.patches import Polygon col_map_f = "CIE 1931 2 Degree Standard Observer" cmfs = first_item(filter_cmfs(col_map_f).values()) wlen_cmfs = [n for n in wavelengths if n > cmfs.shape.start and n < cmfs.shape.end] clr = XYZ_to_plotting_colourspace( wavelength_to_XYZ(wlen_cmfs, cmfs), CCS_ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['E'], apply_cctf_encoding=False) clr = normalise_maximum(clr) clr = CONSTANTS_COLOUR_STYLE.colour.colourspace.cctf_encoding(clr) polygon = Polygon( np.vstack([ [min(wavelengths), 0], np.array([wavelengths, values]).T.tolist(), [max(wavelengths), 0], ]), facecolor='none', edgecolor='none') axis.add_patch(polygon) if opacity < 100: padding = 0 else: padding = 0.1 for dom, col in [(wavelengths - padding, 'black'), (wlen_cmfs, clr)]: axis.bar( x=dom, height=max(values), width=1 + padding, color=col, align='edge', alpha=opacity/100, clip_path=polygon ) pass
def plot_single_cmfs( cmfs: Union[MultiSpectralDistributions, str, Sequence[Union[ MultiSpectralDistributions, str]], ] = "CIE 1931 2 Degree Standard Observer", **kwargs: Any, ) -> Tuple[plt.Figure, plt.Axes]: """ Plot given colour matching functions. Parameters ---------- cmfs Colour matching functions to plot. ``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_multi_cmfs`, :func:`colour.plotting.render`}, See the documentation of the previously listed definitions. Returns ------- :class:`tuple` Current figure and axes. Examples -------- >>> plot_single_cmfs('CIE 1931 2 Degree Standard Observer') ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_Single_CMFS.png :align: center :alt: plot_single_cmfs """ cmfs = cast(MultiSpectralDistributions, first_item(filter_cmfs(cmfs).values())) settings: Dict[str, Any] = { "title": f"{cmfs.strict_name} - Colour Matching Functions" } settings.update(kwargs) return plot_multi_cmfs((cmfs, ), **settings)
def RGB_colourspace_whitepoint_axis_visual(colourspace='ITU-R BT.709', reference_colourspace='CIE xyY', width=2.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Line` class instance representing a given RGB colourspace whitepoint axis. Parameters ---------- colourspace : unicode, optional See :func:`RGB_colourspace_volume_visual` argument for possible values. :class:`colour.RGB_Colourspace` class instance name defining the *RGB* colourspace whitepoint axis to draw. reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'IPT', 'Hunter Lab', 'Hunter Rdab'}**, Reference colourspace to use for colour conversions / transformations. width : numeric, optional Line width. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Line RGB colourspace whitepoint axis. """ colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) XYZ_o = xy_to_XYZ(colourspace.whitepoint + (0, )) XYZ_f = xy_to_XYZ(colourspace.whitepoint + (1.1, )) XYZ_l = np.vstack([XYZ_o, XYZ_f]) illuminant = DEFAULT_PLOTTING_ILLUMINANT points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ_l, illuminant, reference_colourspace), reference_colourspace) line = Line(points, (1, 1, 1), width=width, method=method, parent=parent) return line
def dtype(self): """ Getter and setter property for the continuous signal dtype. Parameters ---------- value : type Value to set the continuous signal dtype with. Returns ------- type Continuous signal dtype. """ if self._signals: return first_item(self._signals.values()).dtype
def plot_single_cmfs(cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given colour matching functions. Parameters ---------- cmfs : unicode or LMS_ConeFundamentals or \ RGB_ColourMatchingFunctions or XYZ_ColourMatchingFunctions, optional Colour matching functions to plot. ``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_multi_cmfs`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_single_cmfs('CIE 1931 2 Degree Standard Observer') ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, <...AxesSubplot...>) .. image:: ../_static/Plotting_Plot_Single_CMFS.png :align: center :alt: plot_single_cmfs """ cmfs = first_item(filter_cmfs(cmfs).values()) settings = { 'title': '{0} - Colour Matching Functions'.format(cmfs.strict_name) } settings.update(kwargs) return plot_multi_cmfs((cmfs, ), **settings)
def domain(self): """ Getter and setter property for the :class:`colour.continuous.Signal` sub-class instances independent domain :math:`x` variable. Parameters ---------- value : array_like Value to set the :class:`colour.continuous.Signal` sub-class instances independent domain :math:`x` variable with. Returns ------- ndarray :class:`colour.continuous.Signal` sub-class instances independent domain :math:`x` variable. """ if self._signals: return first_item(self._signals.values()).domain
def extrapolator_args(self): """ Getter and setter property for the :class:`colour.continuous.Signal` sub-class instances extrapolator instantiation time arguments. Parameters ---------- value : dict Value to set the :class:`colour.continuous.Signal` sub-class instances extrapolator instantiation time arguments to. Returns ------- dict :class:`colour.continuous.Signal` sub-class instances extrapolator instantiation time arguments. """ if self._signals: return first_item(self._signals.values()).extrapolator_args
def extrapolator(self): """ Getter and setter property for the :class:`colour.continuous.Signal` sub-class instances extrapolator type. Parameters ---------- value : type Value to set the :class:`colour.continuous.Signal` sub-class instances extrapolator type with. Returns ------- type :class:`colour.continuous.Signal` sub-class instances extrapolator type. """ if self._signals: return first_item(self._signals.values()).extrapolator
def function(self): """ Getter and setter property for the :class:`colour.continuous.Signal` sub-class instances callable. Parameters ---------- value : object Attribute value. Returns ------- callable :class:`colour.continuous.Signal` sub-class instances callable. Notes ----- - This property is read only. """ if self._signals: return first_item(self._signals.values()).function
def plot_single_cmfs(cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given colour matching functions. Parameters ---------- cmfs : unicode, optional Colour matching functions to plot. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_multi_cmfs`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_single_cmfs('CIE 1931 2 Degree Standard Observer') ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Single_CMFS.png :align: center :alt: plot_single_cmfs """ cmfs = first_item(filter_cmfs(cmfs).values()) settings = { 'title': '{0} - Colour Matching Functions'.format(cmfs.strict_name) } settings.update(kwargs) return plot_multi_cmfs((cmfs.name, ), **settings)
def plot_blackbody_colours( shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. 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 -------- >>> plot_blackbody_colours(SpectralShape(150, 12500, 50)) # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Blackbody_Colours.png :align: center :alt: plot_blackbody_colours """ _figure, axes = artist(**kwargs) cmfs = first_item(filter_cmfs(cmfs).values()) colours = [] temperatures = [] for temperature in shape: sd = sd_blackbody(temperature, cmfs.shape) with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs) RGB = normalise_maximum(XYZ_to_plotting_colourspace(XYZ)) colours.append(RGB) temperatures.append(temperature) x_min, x_max = min(temperatures), max(temperatures) y_min, y_max = 0, 1 padding = 0.1 axes.bar( x=np.array(temperatures) - padding, height=1, width=shape.interval + (padding * shape.interval), color=colours, align='edge') settings = { 'axes': axes, 'bounding_box': (x_min, x_max, y_min, y_max), 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': None, } settings.update(kwargs) return render(**settings)
def plot_single_sd(sd, cmfs='CIE 1931 2 Degree Standard Observer', out_of_gamut_clipping=True, modulate_colours_with_sd_amplitude=False, equalize_sd_amplitude=False, **kwargs): """ Plots given spectral distribution. Parameters ---------- sd : SpectralDistribution Spectral distribution to plot. out_of_gamut_clipping : bool, optional 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. modulate_colours_with_sd_amplitude : bool, optional Whether to modulate the colours with the spectral distribution amplitude. equalize_sd_amplitude : bool, optional Whether to equalize the spectral distribution amplitude. Equalization occurs after the colours modulation thus setting both arguments to *True* will generate a spectrum strip where each wavelength colour is modulated by the spectral distribution amplitude. The usual 5% margin above the spectral distribution is also omitted. cmfs : unicode Standard observer colour matching functions used for spectrum creation. 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. References ---------- :cite:`Spiker2015a` Examples -------- >>> from colour import SpectralDistribution >>> data = { ... 500: 0.0651, ... 520: 0.0705, ... 540: 0.0772, ... 560: 0.0870, ... 580: 0.1128, ... 600: 0.1360 ... } >>> sd = SpectralDistribution(data, name='Custom') >>> plot_single_sd(sd) # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Single_SD.png :align: center :alt: plot_single_sd """ _figure, axes = artist(**kwargs) cmfs = first_item(filter_cmfs(cmfs).values()) sd = sd.copy() sd.interpolator = LinearInterpolator wavelengths = cmfs.wavelengths[np.logical_and( cmfs.wavelengths >= max(min(cmfs.wavelengths), min(sd.wavelengths)), cmfs.wavelengths <= min(max(cmfs.wavelengths), max(sd.wavelengths)), )] values = sd[wavelengths] colours = XYZ_to_plotting_colourspace( wavelength_to_XYZ(wavelengths, cmfs), ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['E'], apply_encoding_cctf=False) if not out_of_gamut_clipping: colours += np.abs(np.min(colours)) colours = normalise_maximum(colours) if modulate_colours_with_sd_amplitude: colours *= (values / np.max(values))[..., np.newaxis] colours = COLOUR_STYLE_CONSTANTS.colour.colourspace.encoding_cctf(colours) if equalize_sd_amplitude: values = np.ones(values.shape) margin = 0 if equalize_sd_amplitude else 0.05 x_min, x_max = min(wavelengths), max(wavelengths) y_min, y_max = 0, max(values) + max(values) * margin polygon = Polygon( np.vstack([ (x_min, 0), tstack([wavelengths, values]), (x_max, 0), ]), facecolor='none', edgecolor='none') axes.add_patch(polygon) padding = 0.1 axes.bar( x=wavelengths - padding, height=max(values), width=1 + padding, color=colours, align='edge', clip_path=polygon) axes.plot(wavelengths, values, color=COLOUR_STYLE_CONSTANTS.colour.dark) settings = { 'axes': axes, 'bounding_box': (x_min, x_max, y_min, y_max), 'title': '{0} - {1}'.format(sd.strict_name, cmfs.strict_name), 'x_label': 'Wavelength $\\lambda$ (nm)', 'y_label': 'Spectral Distribution', } settings.update(kwargs) return render(**settings)
def plot_blackbody_spectral_radiance( temperature=3500, cmfs='CIE 1931 2 Degree Standard Observer', blackbody='VY Canis Major', **kwargs): """ Plots given blackbody spectral radiance. Parameters ---------- temperature : numeric, optional Blackbody temperature. cmfs : unicode, optional Standard observer colour matching functions. blackbody : unicode, optional Blackbody name. 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. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_blackbody_spectral_radiance(3500, blackbody='VY Canis Major') ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Blackbody_Spectral_Radiance.png :align: center :alt: plot_blackbody_spectral_radiance """ figure = plt.figure() figure.subplots_adjust(hspace=COLOUR_STYLE_CONSTANTS.geometry.short / 2) cmfs = first_item(filter_cmfs(cmfs).values()) sd = sd_blackbody(temperature, cmfs.shape) axes = figure.add_subplot(211) settings = { 'axes': axes, 'title': '{0} - Spectral Radiance'.format(blackbody), 'y_label': 'W / (sr m$^2$) / m', } settings.update(kwargs) settings['standalone'] = False plot_single_sd(sd, cmfs.name, **settings) axes = figure.add_subplot(212) with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs) RGB = normalise_maximum(XYZ_to_plotting_colourspace(XYZ)) settings = { 'axes': axes, 'aspect': None, 'title': '{0} - Colour'.format(blackbody), 'x_label': '{0}K'.format(temperature), 'y_label': '', 'x_ticker': False, 'y_ticker': False, } settings.update(kwargs) settings['standalone'] = False figure, axes = plot_single_colour_swatch( ColourSwatch(name='', RGB=RGB), **settings) settings = {'axes': axes, 'standalone': True} settings.update(kwargs) return render(**settings)
def plot_RGB_colourspaces_gamuts(colourspaces=None, reference_colourspace='CIE xyY', segments=8, show_grid=True, grid_segments=10, show_spectral_locus=False, spectral_locus_colour=None, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given *RGB* colourspaces gamuts in given reference colourspace. Parameters ---------- colourspaces : array_like, optional *RGB* colourspaces to plot the gamuts. reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE xy', 'CIE Lab', 'CIE LCHab', 'CIE Luv', 'CIE Luv uv', 'CIE LCHuv', 'CIE UCS', 'CIE UCS uv', 'CIE UVW', 'DIN 99', 'Hunter Lab', 'Hunter Rdab', 'IPT', 'JzAzBz', 'OSA UCS', 'hdr-CIELAB', 'hdr-IPT'}**, Reference colourspace to plot the gamuts into. segments : int, optional Edge segments count for each *RGB* colourspace cubes. show_grid : bool, optional Whether to show a grid at the bottom of the *RGB* colourspace cubes. grid_segments : bool, optional Edge segments count for the grid. show_spectral_locus : bool, optional Whether to show the spectral locus. spectral_locus_colour : array_like, optional Spectral locus colour. cmfs : unicode, optional Standard observer colour matching functions used for spectral locus. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.volume.nadir_grid`}, Please refer to the documentation of the previously listed definitions. face_colours : array_like, optional Face colours array such as `face_colours = (None, (0.5, 0.5, 1.0))`. edge_colours : array_like, optional Edge colours array such as `edge_colours = (None, (0.5, 0.5, 1.0))`. face_alpha : numeric, optional Face opacity value such as `face_alpha = (0.5, 1.0)`. edge_alpha : numeric, optional Edge opacity value such as `edge_alpha = (0.0, 1.0)`. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_RGB_colourspaces_gamuts(['ITU-R BT.709', 'ACEScg', 'S-Gamut']) ... # doctest: +SKIP .. image:: ../_static/Plotting_Plot_RGB_Colourspaces_Gamuts.png :align: center :alt: plot_RGB_colourspaces_gamuts """ if colourspaces is None: colourspaces = ('ITU-R BT.709', 'ACEScg') colourspaces = filter_RGB_colourspaces(colourspaces).values() count_c = len(colourspaces) title = '{0} - {1} Reference Colourspace'.format( ', '.join([colourspace.name for colourspace in colourspaces]), reference_colourspace, ) settings = Structure( **{ 'face_colours': [None] * count_c, 'edge_colours': [None] * count_c, 'face_alpha': [1] * count_c, 'edge_alpha': [1] * count_c, 'title': title, }) settings.update(kwargs) figure = plt.figure() axes = figure.add_subplot(111, projection='3d') illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint points = np.zeros((4, 3)) if show_spectral_locus: cmfs = first_item(filter_cmfs(cmfs).values()) XYZ = cmfs.values points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, illuminant, reference_colourspace), reference_colourspace) points[np.isnan(points)] = 0 c = ((0.0, 0.0, 0.0, 0.5) if spectral_locus_colour is None else spectral_locus_colour) axes.plot( points[..., 0], points[..., 1], points[..., 2], color=c, zorder=1) axes.plot( (points[-1][0], points[0][0]), (points[-1][1], points[0][1]), (points[-1][2], points[0][2]), color=c, zorder=1) quads, RGB_f, RGB_e = [], [], [] for i, colourspace in enumerate(colourspaces): quads_c, RGB = RGB_identity_cube( width_segments=segments, height_segments=segments, depth_segments=segments) XYZ = RGB_to_XYZ( quads_c, colourspace.whitepoint, colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix, ) quads.extend( common_colourspace_model_axis_reorder( XYZ_to_colourspace_model( XYZ, colourspace.whitepoint, reference_colourspace, ), reference_colourspace)) if settings.face_colours[i] is not None: RGB = np.ones(RGB.shape) * settings.face_colours[i] RGB_f.extend( np.hstack([ RGB, np.full((RGB.shape[0], 1), settings.face_alpha[i], DEFAULT_FLOAT_DTYPE) ])) if settings.edge_colours[i] is not None: RGB = np.ones(RGB.shape) * settings.edge_colours[i] RGB_e.extend( np.hstack([ RGB, np.full((RGB.shape[0], 1), settings.edge_alpha[i], DEFAULT_FLOAT_DTYPE) ])) quads = as_float_array(quads) quads[np.isnan(quads)] = 0 if quads.size != 0: for i, axis in enumerate('xyz'): min_a = min(np.min(quads[..., i]), np.min(points[..., i])) max_a = max(np.max(quads[..., i]), np.max(points[..., i])) getattr(axes, 'set_{}lim'.format(axis))((min_a, max_a)) labels = COLOURSPACE_MODELS_LABELS[reference_colourspace] for i, axis in enumerate('xyz'): getattr(axes, 'set_{}label'.format(axis))(labels[i]) if show_grid: if reference_colourspace == 'CIE Lab': limits = np.array([[-450, 450], [-450, 450]]) elif reference_colourspace == 'CIE Luv': limits = np.array([[-650, 650], [-650, 650]]) elif reference_colourspace == 'CIE UVW': limits = np.array([[-850, 850], [-850, 850]]) elif reference_colourspace in ('Hunter Lab', 'Hunter Rdab'): limits = np.array([[-250, 250], [-250, 250]]) else: limits = np.array([[-1.5, 1.5], [-1.5, 1.5]]) quads_g, RGB_gf, RGB_ge = nadir_grid(limits, grid_segments, labels, axes, **settings) quads = np.vstack([quads_g, quads]) RGB_f = np.vstack([RGB_gf, RGB_f]) RGB_e = np.vstack([RGB_ge, RGB_e]) collection = Poly3DCollection(quads) collection.set_facecolors(RGB_f) collection.set_edgecolors(RGB_e) axes.add_collection3d(collection) settings.update({ 'axes': axes, 'axes_visible': False, 'camera_aspect': 'equal' }) settings.update(kwargs) return render(**settings)
def plot_the_blue_sky(cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots the blue sky. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_single_sd`, :func:`colour.plotting.plot_multi_colour_swatches`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_the_blue_sky() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_The_Blue_Sky.png :align: center :alt: plot_the_blue_sky """ figure = plt.figure() figure.subplots_adjust(hspace=COLOUR_STYLE_CONSTANTS.geometry.short / 2) cmfs = first_item(filter_cmfs(cmfs).values()) ASTM_G_173_sd = ASTM_G_173_ETR.copy() rayleigh_sd = sd_rayleigh_scattering() ASTM_G_173_sd.align(rayleigh_sd.shape) sd = rayleigh_sd * ASTM_G_173_sd axes = figure.add_subplot(211) settings = { 'axes': axes, 'title': 'The Blue Sky - Synthetic Spectral Distribution', 'y_label': u'W / m-2 / nm-1', } settings.update(kwargs) settings['standalone'] = False plot_single_sd(sd, cmfs, **settings) axes = figure.add_subplot(212) x_label = ('The sky is blue because molecules in the atmosphere ' 'scatter shorter wavelengths more than longer ones.\n' 'The synthetic spectral distribution is computed as ' 'follows: ' '(ASTM G-173 ETR * Standard Air Rayleigh Scattering).') settings = { 'axes': axes, 'aspect': None, 'title': 'The Blue Sky - Colour', 'x_label': x_label, 'y_label': '', 'x_ticker': False, 'y_ticker': False, } settings.update(kwargs) settings['standalone'] = False blue_sky_color = XYZ_to_plotting_colourspace(sd_to_XYZ(sd)) figure, axes = plot_single_colour_swatch( ColourSwatch('', normalise_maximum(blue_sky_color)), **settings) settings = {'axes': axes, 'standalone': True} settings.update(kwargs) return render(**settings)
def plot_blackbody_colours(shape=SpectralShape(150, 12500, 50), cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots blackbody colours. Parameters ---------- shape : SpectralShape, optional Spectral shape to use as plot boundaries. cmfs : unicode, optional Standard observer colour matching functions. 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 -------- >>> plot_blackbody_colours(SpectralShape(150, 12500, 50)) ... # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Blackbody_Colours.png :align: center :alt: plot_blackbody_colours """ _figure, axes = artist(**kwargs) cmfs = first_item(filter_cmfs(cmfs).values()) colours = [] temperatures = [] for temperature in shape: sd = sd_blackbody(temperature, cmfs.shape) with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs) RGB = normalise_maximum(XYZ_to_plotting_colourspace(XYZ)) colours.append(RGB) temperatures.append(temperature) x_min, x_max = min(temperatures), max(temperatures) y_min, y_max = 0, 1 padding = 0.1 axes.bar(x=np.array(temperatures) - padding, height=1, width=shape.interval + (padding * shape.interval), color=colours, align='edge') settings = { 'axes': axes, 'bounding_box': (x_min, x_max, y_min, y_max), 'title': 'Blackbody Colours', 'x_label': 'Temperature K', 'y_label': None, } settings.update(kwargs) return render(**settings)
def plot_chromaticity_diagram(cmfs='CIE 1931 2 Degree Standard Observer', show_diagram_colours=True, show_spectral_locus=True, method='CIE 1931', **kwargs): """ Plots the *Chromaticity Diagram* according to given method. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used for *Chromaticity Diagram* bounds. show_diagram_colours : bool, optional Whether to display the *Chromaticity Diagram* background colours. show_spectral_locus : bool, optional Whether to display the *Spectral 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_spectral_locus`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram_colours`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_chromaticity_diagram() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram.png :align: center :alt: plot_chromaticity_diagram """ settings = {'uniform': True} settings.update(kwargs) figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) if show_diagram_colours: settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False plot_chromaticity_diagram_colours(**settings) if show_spectral_locus: settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False plot_spectral_locus(**settings) if method == 'CIE 1931': x_label, y_label = 'CIE x', 'CIE y' elif method == 'CIE 1960 UCS': x_label, y_label = 'CIE u', 'CIE v' elif method == 'CIE 1976 UCS': x_label, y_label = 'CIE u\'', 'CIE v\'', else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}'.format( method)) title = '{0} Chromaticity Diagram - {1}'.format(method, cmfs.strict_name) settings.update({ 'axes': axes, 'standalone': True, 'bounding_box': (0, 1, 0, 1), 'title': title, 'x_label': x_label, 'y_label': y_label, }) settings.update(kwargs) return render(**settings)
def plot_multi_sds(sds, cmfs='CIE 1931 2 Degree Standard Observer', use_sds_colours=False, normalise_sds_colours=False, **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. cmfs : unicode, optional Standard observer colour matching functions used for spectrum creation. use_sds_colours : bool, optional Whether to use spectral distributions colours. normalise_sds_colours : bool Whether to normalise spectral distributions colours. 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_multi_sds([sd_1, sd_2]) # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Multi_SDS.png :align: center :alt: plot_multi_sds """ _figure, axes = artist(**kwargs) sds = sds_and_multi_sds_to_sds(sds) cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = ILLUMINANTS_SDS[ COLOUR_STYLE_CONSTANTS.colour.colourspace.illuminant] x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], [] for sd in sds: 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_sds_colours: with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs, illuminant) if normalise_sds_colours: XYZ = normalise_maximum(XYZ, clip=False) RGB = np.clip(XYZ_to_plotting_colourspace(XYZ), 0, 1) axes.plot(wavelengths, values, color=RGB, label=sd.strict_name) else: axes.plot(wavelengths, values, label=sd.strict_name) 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)
def plot_single_sd(sd, cmfs='CIE 1931 2 Degree Standard Observer', out_of_gamut_clipping=True, modulate_colours_with_sd_amplitude=False, equalize_sd_amplitude=False, **kwargs): """ Plots given spectral distribution. Parameters ---------- sd : SpectralDistribution Spectral distribution to plot. out_of_gamut_clipping : bool, optional 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. modulate_colours_with_sd_amplitude : bool, optional Whether to modulate the colours with the spectral distribution amplitude. equalize_sd_amplitude : bool, optional Whether to equalize the spectral distribution amplitude. Equalization occurs after the colours modulation thus setting both arguments to *True* will generate a spectrum strip where each wavelength colour is modulated by the spectral distribution amplitude. The usual 5% margin above the spectral distribution is also omitted. cmfs : unicode Standard observer colour matching functions used for spectrum creation. 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. References ---------- :cite:`Spiker2015a` Examples -------- >>> from colour import SpectralDistribution >>> data = { ... 500: 0.0651, ... 520: 0.0705, ... 540: 0.0772, ... 560: 0.0870, ... 580: 0.1128, ... 600: 0.1360 ... } >>> sd = SpectralDistribution(data, name='Custom') >>> plot_single_sd(sd) # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Single_SD.png :align: center :alt: plot_single_sd """ _figure, axes = artist(**kwargs) cmfs = first_item(filter_cmfs(cmfs).values()) sd = sd.copy() sd.interpolator = LinearInterpolator wavelengths = cmfs.wavelengths[np.logical_and( cmfs.wavelengths >= max(min(cmfs.wavelengths), min(sd.wavelengths)), cmfs.wavelengths <= min(max(cmfs.wavelengths), max(sd.wavelengths)), )] values = sd[wavelengths] colours = XYZ_to_plotting_colourspace( wavelength_to_XYZ(wavelengths, cmfs), ILLUMINANTS['CIE 1931 2 Degree Standard Observer']['E'], apply_cctf_encoding=False) if not out_of_gamut_clipping: colours += np.abs(np.min(colours)) colours = normalise_maximum(colours) if modulate_colours_with_sd_amplitude: colours *= (values / np.max(values))[..., np.newaxis] colours = COLOUR_STYLE_CONSTANTS.colour.colourspace.cctf_encoding(colours) if equalize_sd_amplitude: values = np.ones(values.shape) margin = 0 if equalize_sd_amplitude else 0.05 x_min, x_max = min(wavelengths), max(wavelengths) y_min, y_max = 0, max(values) + max(values) * margin polygon = Polygon(np.vstack([ (x_min, 0), tstack([wavelengths, values]), (x_max, 0), ]), facecolor='none', edgecolor='none') axes.add_patch(polygon) padding = 0.1 axes.bar(x=wavelengths - padding, height=max(values), width=1 + padding, color=colours, align='edge', clip_path=polygon) axes.plot(wavelengths, values, color=COLOUR_STYLE_CONSTANTS.colour.dark) settings = { 'axes': axes, 'bounding_box': (x_min, x_max, y_min, y_max), 'title': '{0} - {1}'.format(sd.strict_name, cmfs.strict_name), 'x_label': 'Wavelength $\\lambda$ (nm)', 'y_label': 'Spectral Distribution', } settings.update(kwargs) return render(**settings)
def RGB_scatter_visual(RGB, colourspace='ITU-R BT.709', reference_colourspace='CIE xyY', symbol='disc', size=4.0, edge_size=0.5, uniform_colour=None, uniform_opacity=1.0, uniform_edge_colour=None, uniform_edge_opacity=1.0, resampling='auto', parent=None): """ Returns a :class:`vispy.scene.visuals.Symbol` class instance representing *RGB* data using given symbols. Parameters ---------- RGB : array_like *RGB* data to draw. colourspace : unicode, optional **{'ITU-R BT.709', 'ACES2065-1', 'ACEScc', 'ACEScg', 'ACESproxy', 'ALEXA Wide Gamut', 'Adobe RGB (1998)', 'Adobe Wide Gamut RGB', 'Apple RGB', 'Best RGB', 'Beta RGB', 'CIE RGB', 'Cinema Gamut', 'ColorMatch RGB', 'DCI-P3', 'DCI-P3+', 'DRAGONcolor', 'DRAGONcolor2', 'Don RGB 4', 'ECI RGB v2', 'ERIMM RGB', 'Ekta Space PS 5', 'Max RGB', 'NTSC', 'Pal/Secam', 'ProPhoto RGB', 'REDcolor', 'REDcolor2', 'REDcolor3', 'REDcolor4', 'RIMM RGB', 'ROMM RGB', 'ITU-R BT.2020', 'Russell RGB', 'S-Gamut', 'S-Gamut3', 'S-Gamut3.Cine', 'SMPTE-C RGB', 'V-Gamut', 'Xtreme RGB', 'sRGB'}**, :class:`colour.RGB_Colourspace` class instance name defining the *RGB* colourspace of the data to draw. reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'IPT', 'Hunter Lab', 'Hunter Rdab'}**, Reference colourspace to use for colour conversions / transformations. symbol : unicode, optional Symbol type to draw. size : numeric, optional Symbol size. edge_size : numeric, optional Symbol edge size. uniform_colour : array_like, optional Uniform symbol colour. uniform_opacity : numeric, optional Uniform symbol opacity. uniform_edge_colour : array_like, optional Uniform symbol edge colour. uniform_edge_opacity : numeric, optional Uniform symbol edge opacity. resampling : numeric or unicode, optional Resampling value, if numeric input, one pixel every `resampling` argument value will be kept. parent : Node, optional Parent of the *RGB* scatter visual in the `SceneGraph`. Returns ------- Symbol *RGB* scatter visual. """ colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) RGB = np.asarray(RGB) if resampling == 'auto': resampling = max(int((0.0078125 * np.average(RGB.shape[0:1])) // 2), 1) RGB = RGB[::resampling, ::resampling].reshape([-1, 3]) XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix) points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, colourspace.whitepoint, reference_colourspace), reference_colourspace) points[np.isnan(points)] = 0 RGB = np.clip(RGB, 0, 1) if uniform_colour is None: RGB = np.hstack([RGB, np.full((RGB.shape[0], 1), uniform_opacity, DEFAULT_FLOAT_DTYPE)]) else: RGB = ColorArray(uniform_colour, alpha=uniform_opacity).rgba if uniform_edge_colour is None: RGB_e = RGB else: RGB_e = ColorArray( uniform_edge_colour, alpha=uniform_edge_opacity).rgba markers = Symbol( symbol=symbol, positions=points, size=size, edge_size=edge_size, face_colour=RGB, edge_colour=RGB_e, parent=parent) return markers
def spectral_locus_visual(reference_colourspace='CIE xyY', cmfs='CIE 1931 2 Degree Standard Observer', width=2.0, uniform_colour=None, uniform_opacity=1.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Line` class instance representing the spectral locus. Parameters ---------- reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'IPT', 'Hunter Lab', 'Hunter Rdab'}**, Reference colourspace to use for colour conversions / transformations. cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. width : numeric, optional Line width. uniform_colour : array_like, optional Uniform symbol colour. uniform_opacity : numeric, optional Uniform symbol opacity. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Line Spectral locus visual. """ cmfs = first_item(filter_cmfs(cmfs).values()) XYZ = cmfs.values XYZ = np.vstack([XYZ, XYZ[0, ...]]) illuminant = DEFAULT_PLOTTING_ILLUMINANT points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, illuminant, reference_colourspace), reference_colourspace) points[np.isnan(points)] = 0 if uniform_colour is None: RGB = normalise_maximum(XYZ_to_sRGB(XYZ, illuminant), axis=-1) RGB = np.hstack([RGB, np.full((RGB.shape[0], 1), uniform_opacity, DEFAULT_FLOAT_DTYPE)]) else: RGB = ColorArray(uniform_colour, alpha=uniform_opacity).rgba line = Line( points, np.clip(RGB, 0, 1), width=width, method=method, parent=parent) return line
def plot_RGB_colourspaces_in_chromaticity_diagram( colourspaces=None, cmfs='CIE 1931 2 Degree Standard Observer', chromaticity_diagram_callable=plot_chromaticity_diagram, method='CIE 1931', show_whitepoints=True, show_pointer_gamut=False, **kwargs): """ Plots given *RGB* colourspaces in the *Chromaticity Diagram* according to given method. Parameters ---------- colourspaces : array_like, optional *RGB* colourspaces to plot. cmfs : unicode, optional Standard observer colour matching functions used for *Chromaticity Diagram* bounds. 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. show_whitepoints : bool, optional Whether to display the *RGB* colourspaces whitepoints. show_pointer_gamut : bool, optional Whether to display the *Pointer's Gamut*. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.plot_pointer_gamut`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_RGB_colourspaces_in_chromaticity_diagram( ... ['ITU-R BT.709', 'ACEScg', 'S-Gamut']) ... # doctest: +SKIP .. image:: ../_static/Plotting_\ Plot_RGB_Colourspaces_In_Chromaticity_Diagram.png :align: center :alt: plot_RGB_colourspaces_in_chromaticity_diagram """ if colourspaces is None: colourspaces = ['ITU-R BT.709', 'ACEScg', 'S-Gamut'] colourspaces = filter_RGB_colourspaces(colourspaces).values() settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) title = '{0}\n{1} - {2} Chromaticity Diagram'.format( ', '.join([colourspace.name for colourspace in colourspaces]), cmfs.name, method) settings = {'axes': axes, 'title': title, 'method': method} settings.update(kwargs) settings['standalone'] = False chromaticity_diagram_callable(**settings) if show_pointer_gamut: settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False plot_pointer_gamut(**settings) if method == 'CIE 1931': def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy x_limit_min, x_limit_max = [-0.1], [0.9] y_limit_min, y_limit_max = [-0.1], [0.9] elif method == 'CIE 1960 UCS': def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy_to_UCS_uv(xy) x_limit_min, x_limit_max = [-0.1], [0.7] y_limit_min, y_limit_max = [-0.2], [0.6] elif method == 'CIE 1976 UCS': def xy_to_ij(xy): """ Converts given *xy* chromaticity coordinates to *ij* chromaticity coordinates. """ return xy_to_Luv_uv(xy) x_limit_min, x_limit_max = [-0.1], [0.7] y_limit_min, y_limit_max = [-0.1], [0.7] else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}}'.format( method)) settings = {'colour_cycle_count': len(colourspaces)} settings.update(kwargs) cycle = colour_cycle(**settings) for colourspace in colourspaces: R, G, B, _A = next(cycle) # RGB colourspaces such as *ACES2065-1* have primaries with # chromaticity coordinates set to 0 thus we prevent nan from being # yield by zero division in later colour transformations. P = np.where( colourspace.primaries == 0, EPSILON, colourspace.primaries, ) P = xy_to_ij(P) W = xy_to_ij(colourspace.whitepoint) axes.plot( (W[0], W[0]), (W[1], W[1]), color=(R, G, B), label=colourspace.name) if show_whitepoints: axes.plot((W[0], W[0]), (W[1], W[1]), 'o', color=(R, G, B)) axes.plot( (P[0, 0], P[1, 0]), (P[0, 1], P[1, 1]), 'o-', color=(R, G, B)) axes.plot( (P[1, 0], P[2, 0]), (P[1, 1], P[2, 1]), 'o-', color=(R, G, B)) axes.plot( (P[2, 0], P[0, 0]), (P[2, 1], P[0, 1]), 'o-', color=(R, G, B)) x_limit_min.append(np.amin(P[..., 0]) - 0.1) y_limit_min.append(np.amin(P[..., 1]) - 0.1) x_limit_max.append(np.amax(P[..., 0]) + 0.1) y_limit_max.append(np.amax(P[..., 1]) + 0.1) bounding_box = ( min(x_limit_min), max(x_limit_max), min(y_limit_min), max(y_limit_max), ) settings.update({ 'standalone': True, 'legend': True, 'bounding_box': bounding_box, }) settings.update(kwargs) return render(**settings)
def plot_RGB_chromaticities_in_chromaticity_diagram( RGB, colourspace='sRGB', chromaticity_diagram_callable=( plot_RGB_colourspaces_in_chromaticity_diagram), method='CIE 1931', scatter_parameters=None, **kwargs): """ Plots given *RGB* colourspace array in the *Chromaticity Diagram* according to given method. Parameters ---------- RGB : array_like *RGB* colourspace array. colourspace : optional, unicode *RGB* colourspace of the *RGB* array. 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. scatter_parameters : dict, optional Parameters for the :func:`plt.scatter` definition, if ``c`` is set to *RGB*, the scatter will use given ``RGB`` colours. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram`, :func:`colour.plotting.diagrams.\ plot_RGB_colourspaces_in_chromaticity_diagram`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> RGB = np.random.random((128, 128, 3)) >>> plot_RGB_chromaticities_in_chromaticity_diagram( ... RGB, 'ITU-R BT.709') ... # doctest: +SKIP .. image:: ../_static/Plotting_\ Plot_RGB_Chromaticities_In_Chromaticity_Diagram_Plot.png :align: center :alt: plot_RGB_chromaticities_in_chromaticity_diagram """ RGB = as_float_array(RGB).reshape(-1, 3) settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() scatter_settings = { 's': 40, 'c': 'RGB', 'marker': 'o', 'alpha': 0.85, } if scatter_parameters is not None: scatter_settings.update(scatter_parameters) settings = dict(kwargs) settings.update({'axes': axes, 'standalone': False}) colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) settings['colourspaces'] = ( ['^{0}$'.format(colourspace.name)] + settings.get('colourspaces', [])) chromaticity_diagram_callable(**settings) use_RGB_colours = scatter_settings['c'].upper() == 'RGB' if use_RGB_colours: RGB = RGB[RGB[:, 1].argsort()] scatter_settings['c'] = np.clip( RGB_to_RGB( RGB, colourspace, COLOUR_STYLE_CONSTANTS.colour.colourspace, apply_encoding_cctf=True).reshape(-1, 3), 0, 1) XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix) if method == 'CIE 1931': ij = XYZ_to_xy(XYZ, colourspace.whitepoint) elif method == 'CIE 1960 UCS': ij = UCS_to_uv(XYZ_to_UCS(XYZ)) elif method == 'CIE 1976 UCS': ij = Luv_to_uv( XYZ_to_Luv(XYZ, colourspace.whitepoint), colourspace.whitepoint) axes.scatter(ij[..., 0], ij[..., 1], **scatter_settings) settings.update({'standalone': True}) settings.update(kwargs) return render(**settings)
def plot_chromaticity_diagram_colours( samples=256, diagram_opacity=1.0, diagram_clipping_path=None, cmfs='CIE 1931 2 Degree Standard Observer', method='CIE 1931', **kwargs): """ Plots the *Chromaticity Diagram* colours according to given method. Parameters ---------- samples : numeric, optional Samples count on one axis. diagram_opacity : numeric, optional Opacity of the *Chromaticity Diagram* colours. diagram_clipping_path : array_like, optional Path of points used to clip the *Chromaticity Diagram* colours. cmfs : unicode, optional Standard observer colour matching functions used for *Chromaticity Diagram* bounds. 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.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_chromaticity_diagram_colours() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_Colours.png :align: center :alt: plot_chromaticity_diagram_colours """ settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint ii, jj = np.meshgrid( np.linspace(0, 1, samples), np.linspace(1, 0, samples)) ij = tstack([ii, jj]) # Avoiding zero division in later colour transformations. ij = np.where(ij == 0, EPSILON, ij) if method == 'CIE 1931': XYZ = xy_to_XYZ(ij) spectral_locus = XYZ_to_xy(cmfs.values, illuminant) elif method == 'CIE 1960 UCS': XYZ = xy_to_XYZ(UCS_uv_to_xy(ij)) spectral_locus = UCS_to_uv(XYZ_to_UCS(cmfs.values)) elif method == 'CIE 1976 UCS': XYZ = xy_to_XYZ(Luv_uv_to_xy(ij)) spectral_locus = Luv_to_uv( XYZ_to_Luv(cmfs.values, illuminant), illuminant) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}}'.format( method)) RGB = normalise_maximum( XYZ_to_plotting_colourspace(XYZ, illuminant), axis=-1) polygon = Polygon( spectral_locus if diagram_clipping_path is None else diagram_clipping_path, facecolor='none', edgecolor='none') axes.add_patch(polygon) # Preventing bounding box related issues as per # https://github.com/matplotlib/matplotlib/issues/10529 image = axes.imshow( RGB, interpolation='bilinear', extent=(0, 1, 0, 1), clip_path=None, alpha=diagram_opacity) image.set_clip_path(polygon) settings = {'axes': axes} settings.update(kwargs) return render(**kwargs)
def plot_chromaticity_diagram(cmfs='CIE 1931 2 Degree Standard Observer', show_diagram_colours=True, show_spectral_locus=True, method='CIE 1931', **kwargs): """ Plots the *Chromaticity Diagram* according to given method. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used for *Chromaticity Diagram* bounds. show_diagram_colours : bool, optional Whether to display the *Chromaticity Diagram* background colours. show_spectral_locus : bool, optional Whether to display the *Spectral 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_spectral_locus`, :func:`colour.plotting.diagrams.plot_chromaticity_diagram_colours`, :func:`colour.plotting.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_chromaticity_diagram() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram.png :align: center :alt: plot_chromaticity_diagram """ settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) if show_diagram_colours: settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False plot_chromaticity_diagram_colours(**settings) if show_spectral_locus: settings = {'axes': axes, 'method': method} settings.update(kwargs) settings['standalone'] = False plot_spectral_locus(**settings) if method == 'CIE 1931': x_label, y_label = 'CIE x', 'CIE y' elif method == 'CIE 1960 UCS': x_label, y_label = 'CIE u', 'CIE v' elif method == 'CIE 1976 UCS': x_label, y_label = 'CIE u\'', 'CIE v\'', else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}}'.format( method)) title = '{0} Chromaticity Diagram - {1}'.format(method, cmfs.strict_name) settings.update({ 'axes': axes, 'standalone': True, 'bounding_box': (0, 1, 0, 1), 'title': title, 'x_label': x_label, 'y_label': y_label, }) settings.update(kwargs) return render(**settings)
def plot_spectral_locus(cmfs='CIE 1931 2 Degree Standard Observer', spectral_locus_colours=None, spectral_locus_labels=None, method='CIE 1931', **kwargs): """ Plots the *Spectral Locus* according to given method. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions defining the *Spectral Locus*. spectral_locus_colours : array_like or unicode, optional *Spectral Locus* colours, if ``spectral_locus_colours`` is set to *RGB*, the colours will be computed according to the corresponding chromaticity coordinates. spectral_locus_labels : array_like, optional Array of wavelength labels used to customise which labels will be drawn around the spectral locus. Passing an empty array will result in no wavelength labels being drawn. 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.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_spectral_locus(spectral_locus_colours='RGB') # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Spectral_Locus.png :align: center :alt: plot_spectral_locus """ if spectral_locus_colours is None: spectral_locus_colours = COLOUR_STYLE_CONSTANTS.colour.dark settings = {'uniform': True} settings.update(kwargs) _figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint wavelengths = cmfs.wavelengths equal_energy = np.array([1 / 3] * 2) if method == 'CIE 1931': ij = XYZ_to_xy(cmfs.values, illuminant) labels = ((390, 460, 470, 480, 490, 500, 510, 520, 540, 560, 580, 600, 620, 700) if spectral_locus_labels is None else spectral_locus_labels) elif method == 'CIE 1960 UCS': ij = UCS_to_uv(XYZ_to_UCS(cmfs.values)) labels = ((420, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 645, 680) if spectral_locus_labels is None else spectral_locus_labels) elif method == 'CIE 1976 UCS': ij = Luv_to_uv(XYZ_to_Luv(cmfs.values, illuminant), illuminant) labels = ((420, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 645, 680) if spectral_locus_labels is None else spectral_locus_labels) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}}'.format( method)) pl_ij = tstack([ np.linspace(ij[0][0], ij[-1][0], 20), np.linspace(ij[0][1], ij[-1][1], 20) ]).reshape(-1, 1, 2) sl_ij = np.copy(ij).reshape(-1, 1, 2) if spectral_locus_colours.upper() == 'RGB': spectral_locus_colours = normalise_maximum( XYZ_to_plotting_colourspace(cmfs.values), axis=-1) if method == 'CIE 1931': XYZ = xy_to_XYZ(pl_ij) elif method == 'CIE 1960 UCS': XYZ = xy_to_XYZ(UCS_uv_to_xy(pl_ij)) elif method == 'CIE 1976 UCS': XYZ = xy_to_XYZ(Luv_uv_to_xy(pl_ij)) purple_line_colours = normalise_maximum( XYZ_to_plotting_colourspace(XYZ.reshape(-1, 3)), axis=-1) else: purple_line_colours = spectral_locus_colours for slp_ij, slp_colours in ((pl_ij, purple_line_colours), (sl_ij, spectral_locus_colours)): line_collection = LineCollection( np.concatenate([slp_ij[:-1], slp_ij[1:]], axis=1), colors=slp_colours) axes.add_collection(line_collection) wl_ij = dict(tuple(zip(wavelengths, ij))) for label in labels: i, j = wl_ij[label] index = bisect.bisect(wavelengths, label) left = wavelengths[index - 1] if index >= 0 else wavelengths[index] right = (wavelengths[index] if index < len(wavelengths) else wavelengths[-1]) dx = wl_ij[right][0] - wl_ij[left][0] dy = wl_ij[right][1] - wl_ij[left][1] ij = np.array([i, j]) direction = np.array([-dy, dx]) normal = (np.array([-dy, dx]) if np.dot( normalise_vector(ij - equal_energy), normalise_vector(direction)) > 0 else np.array([dy, -dx])) normal = normalise_vector(normal) / 30 label_colour = (spectral_locus_colours if is_string(spectral_locus_colours) else spectral_locus_colours[index]) axes.plot( (i, i + normal[0] * 0.75), (j, j + normal[1] * 0.75), color=label_colour) axes.plot(i, j, 'o', color=label_colour) axes.text( i + normal[0], j + normal[1], label, clip_on=True, ha='left' if normal[0] >= 0 else 'right', va='center', fontdict={'size': 'small'}) settings = {'axes': axes} settings.update(kwargs) return render(**kwargs)
def plot_visible_spectrum(cmfs='CIE 1931 2 Degree Standard Observer', out_of_gamut_clipping=True, **kwargs): """ Plots the visible colours spectrum using given standard observer *CIE XYZ* colour matching functions. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used for spectrum creation. out_of_gamut_clipping : bool, optional 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. 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. Returns ------- tuple Current figure and axes. References ---------- :cite:`Spiker2015a` Examples -------- >>> plot_visible_spectrum() # doctest: +ELLIPSIS (<Figure size ... with 1 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Visible_Spectrum.png :align: center :alt: plot_visible_spectrum """ cmfs = first_item(filter_cmfs(cmfs).values()) bounding_box = (min(cmfs.wavelengths), max(cmfs.wavelengths), 0, 1) settings = {'bounding_box': bounding_box, 'y_label': None} settings.update(kwargs) settings['standalone'] = False _figure, axes = plot_single_sd(sd_ones(cmfs.shape), cmfs=cmfs, out_of_gamut_clipping=out_of_gamut_clipping, **settings) # Removing wavelength line as it doubles with the axes spine. axes.lines.pop(0) settings = { 'axes': axes, 'standalone': True, 'title': 'The Visible Spectrum - {0}'.format(cmfs.strict_name), 'x_label': 'Wavelength $\\lambda$ (nm)', } settings.update(kwargs) return render(**settings)
def chromaticity_diagram_construction_visual( cmfs='CIE 1931 2 Degree Standard Observer', width=2.0, method='gl', parent=None): """ Returns a :class:`vispy.scene.visuals.Node` class instance representing the chromaticity diagram construction with the spectral locus. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used to draw the spectral locus. width : numeric, optional Line width. method : unicode, optional **{'gl', 'agg'}**, Line drawing method. parent : Node, optional Parent of the spectral locus visual in the `SceneGraph`. Returns ------- Node Chromaticity diagram construction visual. """ from colour_analysis.visuals import Primitive node = Node(parent=parent) simplex_p = np.array([(1, 0, 0), (0, 1, 0), (0, 0, 1)]) simplex_f = np.array([(0, 1, 2)]) simplex_c = np.array([(1, 1, 1), (1, 1, 1), (1, 1, 1)]) Primitive( simplex_p, simplex_f, uniform_opacity=0.5, vertex_colours=simplex_c, parent=node) simplex_f = np.array([(0, 1, 2), (1, 2, 0), (2, 0, 1)]) Primitive( simplex_p, simplex_f, uniform_opacity=1.0, vertex_colours=simplex_c, wireframe=True, parent=node) lines = [] for XYZ in first_item(filter_cmfs(cmfs).values()).values: lines.append(XYZ * 1.75) lines.append((0, 0, 0)) lines = np.array(lines) Line(lines, (0, 0, 0), width=width, method=method, parent=node) return node
def plot_blackbody_spectral_radiance( temperature=3500, cmfs='CIE 1931 2 Degree Standard Observer', blackbody='VY Canis Major', **kwargs): """ Plots given blackbody spectral radiance. Parameters ---------- temperature : numeric, optional Blackbody temperature. cmfs : unicode, optional Standard observer colour matching functions. blackbody : unicode, optional Blackbody name. 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. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_blackbody_spectral_radiance(3500, blackbody='VY Canis Major') ... # doctest: +ELLIPSIS (<Figure size ... with 2 Axes>, \ <matplotlib.axes._subplots.AxesSubplot object at 0x...>) .. image:: ../_static/Plotting_Plot_Blackbody_Spectral_Radiance.png :align: center :alt: plot_blackbody_spectral_radiance """ figure = plt.figure() figure.subplots_adjust(hspace=COLOUR_STYLE_CONSTANTS.geometry.short / 2) cmfs = first_item(filter_cmfs(cmfs).values()) sd = sd_blackbody(temperature, cmfs.shape) axes = figure.add_subplot(211) settings = { 'axes': axes, 'title': '{0} - Spectral Radiance'.format(blackbody), 'y_label': 'W / (sr m$^2$) / m', } settings.update(kwargs) settings['standalone'] = False plot_single_sd(sd, cmfs.name, **settings) axes = figure.add_subplot(212) with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs) RGB = normalise_maximum(XYZ_to_plotting_colourspace(XYZ)) settings = { 'axes': axes, 'aspect': None, 'title': '{0} - Colour'.format(blackbody), 'x_label': '{0}K'.format(temperature), 'y_label': '', 'x_ticker': False, 'y_ticker': False, } settings.update(kwargs) settings['standalone'] = False figure, axes = plot_single_colour_swatch(ColourSwatch(name='', RGB=RGB), **settings) settings = {'axes': axes, 'standalone': True} settings.update(kwargs) return render(**settings)
def plot_multi_sds(sds, cmfs='CIE 1931 2 Degree Standard Observer', use_sds_colours=False, normalise_sds_colours=False, **kwargs): """ Plots given spectral distributions. Parameters ---------- sds : array_like or MultiSpectralDistribution Spectral distributions or multi-spectral distributions to plot. `sds` can be a single :class:`colour.MultiSpectralDistribution` class instance, a list of :class:`colour.MultiSpectralDistribution` class instances or a list of :class:`colour.SpectralDistribution` class instances. cmfs : unicode, optional Standard observer colour matching functions used for spectrum creation. use_sds_colours : bool, optional Whether to use spectral distributions colours. normalise_sds_colours : bool Whether to normalise spectral distributions colours. 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 ... } >>> spd1 = SpectralDistribution(data_1, name='Custom 1') >>> spd2 = SpectralDistribution(data_2, name='Custom 2') >>> plot_multi_sds([spd1, spd2]) # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Multi_SDs.png :align: center :alt: plot_multi_sds """ _figure, axes = artist(**kwargs) if isinstance(sds, MultiSpectralDistribution): sds = sds.to_sds() else: sds = list(sds) for i, sd in enumerate(sds[:]): if isinstance(sd, MultiSpectralDistribution): sds.remove(sd) sds[i:i] = sd.to_sds() cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = ILLUMINANTS_SDS[ COLOUR_STYLE_CONSTANTS.colour.colourspace.illuminant] x_limit_min, x_limit_max, y_limit_min, y_limit_max = [], [], [], [] for sd in sds: 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_sds_colours: with domain_range_scale('1'): XYZ = sd_to_XYZ(sd, cmfs, illuminant) if normalise_sds_colours: XYZ = normalise_maximum(XYZ, clip=False) RGB = np.clip(XYZ_to_plotting_colourspace(XYZ), 0, 1) axes.plot(wavelengths, values, color=RGB, label=sd.strict_name) else: axes.plot(wavelengths, values, label=sd.strict_name) 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)
def plot_chromaticity_diagram_colours( samples=256, diagram_opacity=1.0, diagram_clipping_path=None, cmfs='CIE 1931 2 Degree Standard Observer', method='CIE 1931', **kwargs): """ Plots the *Chromaticity Diagram* colours according to given method. Parameters ---------- samples : numeric, optional Samples count on one axis. diagram_opacity : numeric, optional Opacity of the *Chromaticity Diagram* colours. diagram_clipping_path : array_like, optional Path of points used to clip the *Chromaticity Diagram* colours. cmfs : unicode, optional Standard observer colour matching functions used for *Chromaticity Diagram* bounds. 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.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_chromaticity_diagram_colours() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Chromaticity_Diagram_Colours.png :align: center :alt: plot_chromaticity_diagram_colours """ settings = {'uniform': True} settings.update(kwargs) figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint ii, jj = np.meshgrid( np.linspace(0, 1, samples), np.linspace(1, 0, samples)) ij = tstack([ii, jj]) if method == 'CIE 1931': XYZ = xy_to_XYZ(ij) spectral_locus = XYZ_to_xy(cmfs.values, illuminant) elif method == 'CIE 1960 UCS': XYZ = xy_to_XYZ(UCS_uv_to_xy(ij)) spectral_locus = UCS_to_uv(XYZ_to_UCS(cmfs.values)) elif method == 'CIE 1976 UCS': XYZ = xy_to_XYZ(Luv_uv_to_xy(ij)) spectral_locus = Luv_to_uv( XYZ_to_Luv(cmfs.values, illuminant), illuminant) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}'.format( method)) RGB = normalise_maximum( XYZ_to_plotting_colourspace(XYZ, illuminant), axis=-1) polygon = Polygon( spectral_locus if diagram_clipping_path is None else diagram_clipping_path, facecolor='none', edgecolor='none') axes.add_patch(polygon) # Preventing bounding box related issues as per # https://github.com/matplotlib/matplotlib/issues/10529 image = axes.imshow( RGB, interpolation='bilinear', extent=(0, 1, 0, 1), clip_path=None, alpha=diagram_opacity) image.set_clip_path(polygon) settings = {'axes': axes} settings.update(kwargs) return render(**kwargs)
def RGB_colourspace_volume_visual(colourspace='ITU-R BT.709', reference_colourspace='CIE xyY', segments=16, uniform_colour=None, uniform_opacity=0.5, wireframe=True, wireframe_colour=None, wireframe_opacity=1.0, parent=None): """ Returns a :class:`vispy.scene.visuals.Node` class instance with one or two :class:`colour_analysis.visuals.Box` class instance children representing a *RGB* colourspace volume visual. Parameters ---------- colourspace : unicode, optional **{'ITU-R BT.709', 'ACES2065-1', 'ACEScc', 'ACEScg', 'ACESproxy', 'ALEXA Wide Gamut', 'Adobe RGB (1998)', 'Adobe Wide Gamut RGB', 'Apple RGB', 'Best RGB', 'Beta RGB', 'CIE RGB', 'Cinema Gamut', 'ColorMatch RGB', 'DCI-P3', 'DCI-P3+', 'DRAGONcolor', 'DRAGONcolor2', 'Don RGB 4', 'ECI RGB v2', 'ERIMM RGB', 'Ekta Space PS 5', 'Max RGB', 'NTSC', 'Pal/Secam', 'ProPhoto RGB', 'REDcolor', 'REDcolor2', 'REDcolor3', 'REDcolor4', 'RIMM RGB', 'ROMM RGB', 'ITU-R BT.2020', 'Russell RGB', 'S-Gamut', 'S-Gamut3', 'S-Gamut3.Cine', 'SMPTE-C RGB', 'V-Gamut', 'Xtreme RGB', 'sRGB'}**, :class:`colour.RGB_Colourspace` class instance name defining the *RGB* colourspace volume to draw. reference_colourspace : unicode **{'CIE XYZ', 'CIE xyY', 'CIE Lab', 'CIE Luv', 'CIE UCS', 'CIE UVW', 'IPT', 'Hunter Lab', 'Hunter Rdab'}**, Reference colourspace to convert the *CIE XYZ* tristimulus values to. segments : int, optional Box segments. uniform_colour : array_like, optional Uniform mesh colour. uniform_opacity : numeric, optional Uniform mesh opacity. wireframe : bool, optional Use wireframe display. Uniform mesh opacity. wireframe_colour : array_like, optional Wireframe mesh colour. wireframe_opacity : numeric, optional Wireframe mesh opacity. parent : Node, optional Parent of the *RGB* colourspace volume visual in the `SceneGraph`. """ node = Node(parent) colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) RGB_cube_f = RGB_identity_cube( width_segments=segments, height_segments=segments, depth_segments=segments, uniform_colour=uniform_colour, uniform_opacity=uniform_opacity, vertex_colours=not uniform_colour, parent=node) vertices = RGB_cube_f.mesh_data.get_vertices() XYZ = RGB_to_XYZ(vertices, colourspace.whitepoint, colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix) value = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, colourspace.whitepoint, reference_colourspace), reference_colourspace) value[np.isnan(value)] = 0 RGB_cube_f.mesh_data.set_vertices(value) if wireframe: RGB_cube_w = RGB_identity_cube( width_segments=segments, height_segments=segments, depth_segments=segments, uniform_colour=wireframe_colour, uniform_opacity=wireframe_opacity, vertex_colours=not wireframe_colour, wireframe=True, parent=node) RGB_cube_w.mesh_data.set_vertices(value) return node
def plot_spectral_locus(cmfs='CIE 1931 2 Degree Standard Observer', spectral_locus_colours=None, spectral_locus_labels=None, method='CIE 1931', **kwargs): """ Plots the *Spectral Locus* according to given method. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions defining the *Spectral Locus*. spectral_locus_colours : array_like or unicode, optional *Spectral Locus* colours, if ``spectral_locus_colours`` is set to *RGB*, the colours will be computed according to the corresponding chromaticity coordinates. spectral_locus_labels : array_like, optional Array of wavelength labels used to customise which labels will be drawn around the spectral locus. Passing an empty array will result in no wavelength labels being drawn. 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.render`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> plot_spectral_locus(spectral_locus_colours='RGB') # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Spectral_Locus.png :align: center :alt: plot_spectral_locus """ if spectral_locus_colours is None: spectral_locus_colours = COLOUR_STYLE_CONSTANTS.colour.dark settings = {'uniform': True} settings.update(kwargs) figure, axes = artist(**settings) method = method.upper() cmfs = first_item(filter_cmfs(cmfs).values()) illuminant = COLOUR_STYLE_CONSTANTS.colour.colourspace.whitepoint wavelengths = cmfs.wavelengths equal_energy = np.array([1 / 3] * 2) if method == 'CIE 1931': ij = XYZ_to_xy(cmfs.values, illuminant) labels = ((390, 460, 470, 480, 490, 500, 510, 520, 540, 560, 580, 600, 620, 700) if spectral_locus_labels is None else spectral_locus_labels) elif method == 'CIE 1960 UCS': ij = UCS_to_uv(XYZ_to_UCS(cmfs.values)) labels = ((420, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 645, 680) if spectral_locus_labels is None else spectral_locus_labels) elif method == 'CIE 1976 UCS': ij = Luv_to_uv(XYZ_to_Luv(cmfs.values, illuminant), illuminant) labels = ((420, 440, 450, 460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590, 600, 610, 620, 630, 645, 680) if spectral_locus_labels is None else spectral_locus_labels) else: raise ValueError( 'Invalid method: "{0}", must be one of ' '{\'CIE 1931\', \'CIE 1960 UCS\', \'CIE 1976 UCS\'}'.format( method)) pl_ij = tstack([ np.linspace(ij[0][0], ij[-1][0], 20), np.linspace(ij[0][1], ij[-1][1], 20) ]).reshape(-1, 1, 2) sl_ij = np.copy(ij).reshape(-1, 1, 2) if spectral_locus_colours.upper() == 'RGB': spectral_locus_colours = normalise_maximum( XYZ_to_plotting_colourspace(cmfs.values), axis=-1) if method == 'CIE 1931': XYZ = xy_to_XYZ(pl_ij) elif method == 'CIE 1960 UCS': XYZ = xy_to_XYZ(UCS_uv_to_xy(pl_ij)) elif method == 'CIE 1976 UCS': XYZ = xy_to_XYZ(Luv_uv_to_xy(pl_ij)) purple_line_colours = normalise_maximum( XYZ_to_plotting_colourspace(XYZ.reshape(-1, 3)), axis=-1) else: purple_line_colours = spectral_locus_colours for slp_ij, slp_colours in ((pl_ij, purple_line_colours), (sl_ij, spectral_locus_colours)): line_collection = LineCollection( np.concatenate([slp_ij[:-1], slp_ij[1:]], axis=1), colors=slp_colours) axes.add_collection(line_collection) wl_ij = dict(tuple(zip(wavelengths, ij))) for label in labels: i, j = wl_ij[label] index = bisect.bisect(wavelengths, label) left = wavelengths[index - 1] if index >= 0 else wavelengths[index] right = (wavelengths[index] if index < len(wavelengths) else wavelengths[-1]) dx = wl_ij[right][0] - wl_ij[left][0] dy = wl_ij[right][1] - wl_ij[left][1] ij = np.array([i, j]) direction = np.array([-dy, dx]) normal = (np.array([-dy, dx]) if np.dot( normalise_vector(ij - equal_energy), normalise_vector(direction)) > 0 else np.array([dy, -dx])) normal = normalise_vector(normal) / 30 label_colour = (spectral_locus_colours if is_string(spectral_locus_colours) else spectral_locus_colours[index]) axes.plot( (i, i + normal[0] * 0.75), (j, j + normal[1] * 0.75), color=label_colour) axes.plot(i, j, 'o', color=label_colour) axes.text( i + normal[0], j + normal[1], label, clip_on=True, ha='left' if normal[0] >= 0 else 'right', va='center', fontdict={'size': 'small'}) settings = {'axes': axes} settings.update(kwargs) return render(**kwargs)
def plot_visible_spectrum(cmfs='CIE 1931 2 Degree Standard Observer', out_of_gamut_clipping=True, **kwargs): """ Plots the visible colours spectrum using given standard observer *CIE XYZ* colour matching functions. Parameters ---------- cmfs : unicode, optional Standard observer colour matching functions used for spectrum creation. out_of_gamut_clipping : bool, optional 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. 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. Returns ------- tuple Current figure and axes. References ---------- :cite:`Spiker2015a` Examples -------- >>> plot_visible_spectrum() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Visible_Spectrum.png :align: center :alt: plot_visible_spectrum """ cmfs = first_item(filter_cmfs(cmfs).values()) bounding_box = (min(cmfs.wavelengths), max(cmfs.wavelengths), 0, 1) settings = {'bounding_box': bounding_box, 'y_label': None} settings.update(kwargs) settings['standalone'] = False _figure, axes = plot_single_sd( sd_ones(cmfs.shape), cmfs=cmfs, out_of_gamut_clipping=out_of_gamut_clipping, **settings) # Removing wavelength line as it doubles with the axes spine. axes.lines.pop(0) settings = { 'axes': axes, 'standalone': True, 'title': 'The Visible Spectrum - {0}'.format(cmfs.strict_name), 'x_label': 'Wavelength $\\lambda$ (nm)', } settings.update(kwargs) return render(**settings)
def plot_RGB_scatter(RGB, colourspace, reference_colourspace='CIE xyY', colourspaces=None, segments=8, show_grid=True, grid_segments=10, show_spectral_locus=False, spectral_locus_colour=None, points_size=12, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots given *RGB* colourspace array in a scatter plot. Parameters ---------- RGB : array_like *RGB* colourspace array. colourspace : RGB_Colourspace *RGB* colourspace of the *RGB* array. reference_colourspace : unicode, optional **{'CIE XYZ', 'CIE xyY', 'CIE xy', 'CIE Lab', 'CIE LCHab', 'CIE Luv', 'CIE Luv uv', 'CIE LCHuv', 'CIE UCS', 'CIE UCS uv', 'CIE UVW', 'DIN 99', 'Hunter Lab', 'Hunter Rdab', 'IPT', 'JzAzBz', 'OSA UCS', 'hdr-CIELAB', 'hdr-IPT'}**, Reference colourspace for colour conversion. colourspaces : array_like, optional *RGB* colourspaces to plot the gamuts. segments : int, optional Edge segments count for each *RGB* colourspace cubes. show_grid : bool, optional Whether to show a grid at the bottom of the *RGB* colourspace cubes. grid_segments : bool, optional Edge segments count for the grid. show_spectral_locus : bool, optional Whether to show the spectral locus. spectral_locus_colour : array_like, optional Spectral locus colour. points_size : numeric, optional Scatter points size. cmfs : unicode, optional Standard observer colour matching functions used for spectral locus. Other Parameters ---------------- \\**kwargs : dict, optional {:func:`colour.plotting.artist`, :func:`colour.plotting.plot_RGB_colourspaces_gamuts`}, Please refer to the documentation of the previously listed definitions. Returns ------- tuple Current figure and axes. Examples -------- >>> RGB = np.random.random((128, 128, 3)) >>> plot_RGB_scatter(RGB, 'ITU-R BT.709') # doctest: +SKIP .. image:: ../_static/Plotting_Plot_RGB_Scatter.png :align: center :alt: plot_RGB_scatter """ colourspace = first_item(filter_RGB_colourspaces(colourspace).values()) if colourspaces is None: colourspaces = (colourspace.name, ) count_c = len(colourspaces) settings = Structure( **{ 'face_colours': [None] * count_c, 'edge_colours': [(0.25, 0.25, 0.25)] * count_c, 'face_alpha': [0.0] * count_c, 'edge_alpha': [0.1] * count_c, }) settings.update(kwargs) settings['standalone'] = False plot_RGB_colourspaces_gamuts( colourspaces=colourspaces, reference_colourspace=reference_colourspace, segments=segments, show_grid=show_grid, grid_segments=grid_segments, show_spectral_locus=show_spectral_locus, spectral_locus_colour=spectral_locus_colour, cmfs=cmfs, **settings) XYZ = RGB_to_XYZ(RGB, colourspace.whitepoint, colourspace.whitepoint, colourspace.RGB_to_XYZ_matrix) points = common_colourspace_model_axis_reorder( XYZ_to_colourspace_model(XYZ, colourspace.whitepoint, reference_colourspace), reference_colourspace) axes = plt.gca() axes.scatter( points[..., 0], points[..., 1], points[..., 2], color=np.reshape(RGB, (-1, 3)), s=points_size) settings.update({'axes': axes, 'standalone': True}) settings.update(kwargs) return render(**settings)
def plot_single_sd_rayleigh_scattering( CO2_concentration=STANDARD_CO2_CONCENTRATION, temperature=STANDARD_AIR_TEMPERATURE, pressure=AVERAGE_PRESSURE_MEAN_SEA_LEVEL, latitude=DEFAULT_LATITUDE, altitude=DEFAULT_ALTITUDE, cmfs='CIE 1931 2 Degree Standard Observer', **kwargs): """ Plots a single *Rayleigh* scattering spectral distribution. Parameters ---------- CO2_concentration : numeric, optional :math:`CO_2` concentration in parts per million (ppm). temperature : numeric, optional Air temperature :math:`T[K]` in kelvin degrees. pressure : numeric Surface pressure :math:`P` of the measurement site. latitude : numeric, optional Latitude of the site in degrees. altitude : numeric, optional Altitude of the site in meters. cmfs : unicode, optional Standard observer colour matching functions. 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. Examples -------- >>> plot_single_sd_rayleigh_scattering() # doctest: +SKIP .. image:: ../_static/Plotting_Plot_Single_SD_Rayleigh_Scattering.png :align: center :alt: plot_single_sd_rayleigh_scattering """ title = 'Rayleigh Scattering' cmfs = first_item(filter_cmfs(cmfs).values()) settings = {'title': title, 'y_label': 'Optical Depth'} settings.update(kwargs) sd = sd_rayleigh_scattering(cmfs.shape, CO2_concentration, temperature, pressure, latitude, altitude) return plot_single_sd(sd, **settings)