<jupyter_start><jupyter_text>A visual representation of named colorsI looked into word embeddings for my bachelor thesis and stumbled into a great GitHub Gist by [<NAME>](https://gist.github.com/aparrish/2f562e3737544cf29aaf1af30362f469) titled "Understanding word vectors". Her Gist is very educational, explaining everything from the ground up. However, the section about colors as vectors did not show the colors being discussed. Since I am a visual learner, I wanted to implement some way of plotting the colors to see them. I realized that this could be a handy tool in other circumstances, and I have extracted what I made and modified it to work without her Gists context.  Color basisLet's start by loading the color information from <NAME>'s GitHub repository containing a [JSON file](https://github.com/dariusk/corpora/blob/master/data/colors/xkcd.json) with the xkcd color names and values.<jupyter_code>import urllib.request, json

# read json data
with urllib.request.urlopen("https://raw.githubusercontent.com/dariusk/corpora/master/data/colors/xkcd.json") as url:
    color_data = json.loads(url.read().decode())<jupyter_output><empty_output><jupyter_text>I want to make a dictionary that holds the hex, integer, and normalized integer values, so the first step is to create a function that converts hex to a tuple with RGB values.<jupyter_code>def hex_to_int(color):
    """
    Converts hexcolor codes to tuple of integers.

    Args:
        color (str): hex color code.

    Returns:
        tuple: RGB values as integers.
    """
    color = color.lstrip("#")
    return int(color[:2], 16), int(color[2:4], 16), int(color[4:6], 16)<jupyter_output><empty_output><jupyter_text>Now, I am ready to define the new color dictionary, which holds all the mentioned values.<jupyter_code># Define one dictionary with name as key
colors: dict = {}

for i in color_data["colors"]:
    temp = list(i.values())

    # hex color as value
    val_hex = temp[1]

    # int (RGB 0-255) color as value
    val_int = hex_to_int(temp[1])

    # normalized int (0-1) color as value
    val_norm = tuple([x / 255 for x in val_int])

    # combine to dict
    colors[temp[0]] = {"hex": val_hex, "int": val_int, "norm": val_norm}<jupyter_output><empty_output><jupyter_text>Let's see look at some results.<jupyter_code>print("Sample of 5 colors with hex values")
names = [x[0] for x in list(colors.items())[0:5]]
values = [colors[x]["hex"] for x in names]
display(list(zip(names, values)))

print("Sample of 5 colors with int values")
names = [x[0] for x in list(colors.items())[0:5]]
values = [colors[x]["int"] for x in names]
display(list(zip(names, values)))

print("Sample of 5 colors with normalized int values")
names = [x[0] for x in list(colors.items())[0:5]]
values = [colors[x]["norm"] for x in names]
display(list(zip(names, values)))<jupyter_output>Sample of 5 colors with hex values<jupyter_text>Let's test if we can give a color name as input and get the values back.<jupyter_code>print("Test for the color 'red':")
display(colors["red"])<jupyter_output>Test for the color 'red':<jupyter_text>Making it visibleThere was already an excellent function for plotting colors in the [Matplotlib documentation](https://matplotlib.org/3.1.0/gallery/color/named_colors.html), so I copied it and made some small changes to better suit my needs.<jupyter_code>import matplotlib.pyplot as plt
import matplotlib.colors as mcolors


def plot_colortable(colors, title="Colors", sort_colors=True, emptycols=0, title_size=18, text_size=14):

    cell_width = 212
    cell_height = 22
    swatch_width = 48
    margin = 12
    topmargin = 40

    # Sort colors by hue, saturation, value and name.
    if sort_colors is True:
        by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgb(color))),
                         name)
                        for name, color in colors.items())
        names = [name for hsv, name in by_hsv]
    else:
        names = list(colors)

    n = len(names)
    ncols = 4 - emptycols
    nrows = n // ncols + int(n % ncols > 0)

    width = cell_width * 4 + 2 * margin
    height = cell_height * nrows + margin + topmargin
    dpi = 72

    fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
    fig.subplots_adjust(margin/width, margin/height,
                        (width-margin)/width, (height-topmargin)/height)
    ax.set_xlim(0, cell_width * 4)
    ax.set_ylim(cell_height * (nrows-0.5), -cell_height/2.)
    ax.yaxis.set_visible(False)
    ax.xaxis.set_visible(False)
    ax.set_axis_off()
    ax.set_title(title, fontsize=title_size, loc="left", pad=10)

    for i, name in enumerate(names):
        row = i % nrows
        col = i // nrows
        y = row * cell_height

        swatch_start_x = cell_width * col
        swatch_end_x = cell_width * col + swatch_width
        text_pos_x = cell_width * col + swatch_width + 7

        ax.text(text_pos_x, y, name, fontsize=text_size,
                horizontalalignment='left',
                verticalalignment='center')

        ax.hlines(y, swatch_start_x, swatch_end_x,
                  color=colors[name], linewidth=18)

    return fig<jupyter_output><empty_output><jupyter_text>Since a predefined function is used for plotting, a function that generates the needed input is defined.<jupyter_code>def make_selection_dict(names, color_index, val_type="hex"):
    """
    Makes a dictionary for the selected colors and their values.

    Args:
        names (list): color names
        color_index (dict): All avaliable colors.
        val_type (str, optional): value return type. Defaults to "hex".

    Returns:
        [dict]: color names and values.
    """
    value_list: list = []
    
    # Makes a list of color values based on the input and desired return type.
    for i in names:
        value_list.append(color_index[i][val_type])
    
    # Combines the names and values in a dictionary.
    return {k: v for k, v in zip(names, value_list)}<jupyter_output><empty_output><jupyter_text>Let's make a list of colors and test that the new function returns "hex" values.<jupyter_code>color_selection = ["red", "green", "blue"]

display(selection := make_selection_dict(color_selection, colors, "hex"))<jupyter_output><empty_output><jupyter_text>Now the time to see the actual colors is here.<jupyter_code>plot_colortable(selection, sort_colors=False, emptycols=1);<jupyter_output><empty_output><jupyter_text>Finding shades of a colorAllison's Gist had some functions that enabled us to find the n closest colors to our selection based on euclidean distance. I have combined some of her functions and made alterations to them to better suit my needs.<jupyter_code>def closest(color_index, color_val, n=10):
    """
    Defines a list of n closest colors to the input color.

    Args:
        color_index (dict): All avaliable colors.
        color_val (dict): Base color.
        n (int, optional): Number of closest colors. Defaults to 10.

    Returns:
        list: Names of closest colors.
    """
    from scipy.spatial.distance import euclidean
    closest = []
    if isinstance(color_val, dict):
        for key in sorted(color_index.keys(),
                          key=lambda x: euclidean(color_val["int"],
                                                  color_index[x]["int"]))[:n]:
            closest.append(key)
    elif isinstance(color_val, list):
        for key in sorted(
                color_index.keys(),
                key=lambda x: euclidean(color_val, color_index[x]["int"]))[:n]:
            closest.append(key)
    return closest<jupyter_output><empty_output><jupyter_text>Let's find the 6 closest colors to "red".<jupyter_code>color_selection = closest(colors, colors["red"], 6)
selection = make_selection_dict(color_selection, colors, "hex")  # <-- using hex
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Let's find the 6 closest colors to "green".<jupyter_code>color_selection = closest(colors, colors["green"], 6)
selection = make_selection_dict(color_selection, colors, "norm")  # <-- using norm
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Let's find the 12 closest colors to "pure blue", by using the RGB values.<jupyter_code>color_selection = closest(colors, [3, 6, 223], 12)
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Playing with vectorsThe following functions are copied as they were from the previously mentioned Gist since they do the intended job, and I don't see any need to alter them.  Subtract one color from anotherLet's test subtracting "magenta" from "cyan".<jupyter_code>def subtractv(coord1, coord2):
    return [c1 - c2 for c1, c2 in zip(coord1, coord2)]

# Have to use "int" in the subtractv function
color_selection = closest(colors, subtractv(colors['magenta']["int"], colors['cyan']["int"]), 12)
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Add one color to anotherLet's test adding "royal" with "teal".<jupyter_code>def addv(coord1, coord2):
    return [c1 + c2 for c1, c2 in zip(coord1, coord2)]

# Have to use "int" in the addv function
color_selection = closest(colors, addv(colors['royal']["int"], colors['teal']["int"]), 12)
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Find the average of a listLet's test finding the average of black and white.<jupyter_code>def meanv(coords):
    # assumes every item in coords has same length as item 0
    sumv = [0] * len(coords[0])
    for item in coords:
        for i in range(len(item)):
            sumv[i] += item[i]
    mean = [0] * len(sumv)
    for i in range(len(sumv)):
        mean[i] = float(sumv[i]) / len(coords)
    return mean
meanv([[0, 1], [2, 2], [4, 3]])

# Have to use "int" in the meanv function
color_selection = closest(colors, meanv([colors['black']["int"], colors['white']["int"]]), 12)
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output><jupyter_text>Finding random colors<jupyter_code>import random

color_selection = random.sample(colors.keys(), 12)
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, sort_colors=False, emptycols=1);<jupyter_output><empty_output><jupyter_text>Every n color in range<jupyter_code>color_selection = [list(colors.keys())[x] for x in range(0, 37, 3)]
selection = make_selection_dict(color_selection, colors, "hex")
plot_colortable(selection, emptycols=1);<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11106987102162012, 'fraction_numerical': 0.0145680616126937, 'mean_word_length': 4.156937799043062, 'pattern_counts': {'":': 3, '<': 75, '<?xml version=': 0, '>': 74, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '18', 'dir': 'jupyter-structured-clean-dedup', 'id': '498025', 'license': 'MIT', 'n_tokens_mistral': 3541, 'n_tokens_neox': 3377, 'n_words': 1037, 'path': 'assets/notebooks/A visual representation of named colors.ipynb', 'repo_name': 'lewiuberg/lewiuberg.github.io', 'size': '10793'}