Example #1
0
    def assert_round_trip(self, color, space):
        """Cycle through all the other colors and convert to them and back and check the results."""

        c1 = Color(color).convert(space)
        for space in SPACES:
            # Print the color space to easily identify which color space broke.
            c2 = c1.convert(space)
            c2.convert(c1.space(), in_place=True)
            # Catch cases where we are really close to 360 which should wrap to 0
            for c in (c1, c2):
                if isinstance(c._space, Cylindrical):
                    if util.round_half_up(util.no_nan(c.hue),
                                          c.PRECISION) == 360:
                        c.hue = 0
            # Run rounded string back through parsing in case we hit something like a hue that needs normalization.
            str1 = Color(c1.to_string(color=True,
                                      fit=False)).to_string(color=True,
                                                            fit=False)
            str2 = Color(c2.to_string(color=True,
                                      fit=False)).to_string(color=True,
                                                            fit=False)
            # Print failing results for debug purposes
            if str1 != str2:
                print('----- Convert: {} <=> {} -----'.format(
                    c1.space(), space))
                print('Original: ', color.to_string(color=True, fit=False))
                print(c1.space() + ': ', str1, c1.coords())
                print(space + ': ', str2, c2.coords())
                assert str1 == str2
Example #2
0
def cie_diagram(mode="1931",
                observer="2deg",
                colorize=True,
                opacity=1,
                rgb_spaces=None,
                white_points=None,
                theme='light',
                title='',
                show_labels=True,
                axis=True,
                show_legend=True,
                black_body=False):
    """CIE diagram."""

    opt = DiagramOptions(theme=theme,
                         mode=mode,
                         observer=observer,
                         title=title)
    figure = plt.figure()
    ax = plt.axes(xlabel=opt.axis_labels[0], ylabel=opt.axis_labels[1])
    ax.set_aspect('equal')
    if axis is False:
        plt.axis('off')
    figure.add_axes(ax)
    plt.title(opt.title)
    if show_labels:
        plt.margins(0.15)

    xs = []
    ys = []
    annotations = []

    # Get points for the spectral locus
    for k, v in opt.observer.items():
        # Get the XYZ values in the correct format
        if opt.mode == "1931":
            x, y = util.xyz_to_xyY(v, (0.31270, 0.32900))[:2]
            xs.append(x)
            ys.append(y)
        elif opt.mode == "1976":
            x, y = util.xyz_to_uv(v)
            xs.append(x)
            ys.append(y)
        else:
            x, y = util.xy_to_uv_1960(
                util.xyz_to_xyY(v, (0.31270, 0.32900))[:2])
            xs.append(x)
            ys.append(y)

        # Prepare annotation labels for all points on the spectral locus.
        if k in labels:
            annotations.append((k, (x, y)))

    xs, ys = get_spline(xs, ys, len(xs) * 3)

    # Draw the bottom purple line
    xs.append(xs[0])
    ys.append(ys[0])

    # Generate fill colors for inside the spectral locus
    if colorize:
        px = []
        py = []
        c = []
        path = mpltpath.Path(list(zip(xs, ys)))
        for r in itertools.product(
            (x / RESOLUTION for x in range(0, RESOLUTION + 1)),
            (x / RESOLUTION for x in range(0, RESOLUTION + 1))):
            srgb = Color('srgb', [])
            if path.contains_point(r):
                if opt.mode == "1931":
                    xyz = util.xy_to_xyz(r)
                elif opt.mode == "1976":
                    xyz = util.xy_to_xyz(util.uv_to_xy(r))
                else:
                    xyz = util.xy_to_xyz(util.uv_1960_to_xy(r))
                px.append(r[0])
                py.append(r[1])
                srgb.update('xyz-d65', xyz, opacity)
                m = max(srgb.coords())
                srgb.update('srgb', [(i / m if m != 0 else 0)
                                     for i in srgb.coords()], srgb.alpha)
                c.append(srgb.to_string(hex=True, fit="clip"))
        plt.scatter(px, py, edgecolors=None, c=c, s=1)

    # Plot spectral locus and label it
    plt.plot(xs,
             ys,
             color=opt.locus_line_color if colorize else opt.default_color,
             marker="",
             linewidth=1.5,
             markersize=2,
             antialiased=True)

    if show_labels:
        # Label points
        ax = []
        ay = []
        for annotate in annotations:
            offset = opt.locus_labels(annotate[0])
            ax.append(annotate[1][0])
            ay.append(annotate[1][1])
            plt.annotate('{:d}'.format(annotate[0]),
                         annotate[1],
                         size=8,
                         color=opt.locus_label_color,
                         textcoords="offset points",
                         xytext=offset,
                         ha='center')
        plt.scatter(
            ax,
            ay,
            marker=".",
            color=opt.locus_point_color if not colorize else opt.default_color,
            zorder=100)

    # Add any specified white points.
    if white_points:
        wx = []
        wy = []
        annot = []
        for wp in white_points:
            w = WHITES[wp]
            annot.append(wp)
            if opt.mode == '1931':
                wx.append(w[0])
                wy.append(w[1])
            elif opt.mode == '1976':
                uv = util.xyz_to_uv(util.xy_to_xyz(w))
                wx.append(uv[0])
                wy.append(uv[1])
            else:
                uv = util.xy_to_uv_1960(w)
                wx.append(uv[0])
                wy.append(uv[1])
        plt.scatter(wx,
                    wy,
                    marker=".",
                    color=opt.default_colorized_color
                    if colorize else opt.default_color)
        for pt, a in zip(zip(wx, wy), annot):
            plt.annotate(a,
                         pt,
                         size=8,
                         color=opt.default_colorized_color
                         if colorize else opt.default_color,
                         textcoords="offset points",
                         xytext=(15, -3),
                         ha='center')

    # Show the black body (Planckian locus) curve
    # Work in progress.
    if black_body and opt.mode != '1976':
        uaxis = []
        vaxis = []
        bres = 20
        boffset = 1000
        brange = 24000
        for cct in range(0, bres + 1):
            t = cct / bres * brange + boffset
            bu, bv = black_body_curve(t, opt.mode)
            uaxis.append(bu)
            vaxis.append(bv)
        uaxis, vaxis = get_spline(uaxis, vaxis, len(uaxis) * 4)
        plt.plot(uaxis,
                 vaxis,
                 color=opt.default_colorized_color
                 if colorize else opt.default_color,
                 marker="",
                 linewidth=1,
                 markersize=0,
                 antialiased=True)
        # `plt.scatter(uaxis, vaxis, c=opt.default_color)`

    # Draw RGB triangles if one is specified
    if rgb_spaces:
        temp = Color('srgb', [])
        for space, color in rgb_spaces:
            if opt.mode == '1931':
                red = temp.mutate(space, [1, 0, 0]).xy()
                green = temp.mutate(space, [0, 1, 0]).xy()
                blue = temp.mutate(space, [0, 0, 1]).xy()
            elif opt.mode == '1976':
                red = temp.mutate(space, [1, 0, 0]).uv()
                green = temp.mutate(space, [0, 1, 0]).uv()
                blue = temp.mutate(space, [0, 0, 1]).uv()
            else:
                red = temp.mutate(space, [1, 0, 0]).uv('1960')
                green = temp.mutate(space, [0, 1, 0]).uv('1960')
                blue = temp.mutate(space, [0, 0, 1]).uv('1960')
            plt.plot([red[0], green[0], blue[0], red[0]],
                     [red[1], green[1], blue[1], red[1]],
                     marker='o',
                     color=color,
                     label=space,
                     linewidth=2,
                     markersize=0,
                     path_effects=[
                         path_effects.SimpleLineShadow(alpha=0.2,
                                                       offset=(1, -1)),
                         path_effects.Normal()
                     ])

    # We current only add labels when drawing RGB triangles
    if rgb_spaces and show_legend:
        ax.legend()