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 = get_cmfs(cmfs)

    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)))
    triangulation = Delaunay(ij, qhull_options='QJ')
    RGB = normalise(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 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'}

        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.
    edge_size : numeric, optional
        Symbol edge size.
    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 = get_cmfs(cmfs)
    XYZ = cmfs.values

    XYZ = np.vstack((XYZ, XYZ[0, ...]))

    illuminant = DEFAULT_PLOTTING_ILLUMINANT

    points = XYZ_to_reference_colourspace(XYZ, illuminant, reference_colourspace)
    points[np.isnan(points)] = 0

    if uniform_colour is None:
        RGB = normalise(XYZ_to_sRGB(XYZ, illuminant), axis=-1)
        RGB = np.hstack((RGB, np.full((RGB.shape[0], 1), uniform_opacity)))
    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