Today, I am continuing my experiments from yesterday in goofing around with LLMs via the edsl pacakage. Today, my vision is as follows:

  1. Have ChatGPT generate a list of emotions.
  2. Using edsl, map all the motions to colors in RGB color space.
  3. Visualize the results

This should be fairly straightforward, so let’s do it. First, here is a list of emotions from chatGPT:

emotions = [
    "Happiness",
    "Sadness",
    "Anger",
    "Fear",
    "Disgust",
    "Surprise",
    "Love",
    "Joy",
    "Anxiety",
    "Excitement",
    "Jealousy",
    "Gratitude",
    "Contentment",
    "Hope",
    "Pride",
    "Shame",
    "Guilt",
    "Envy",
    "Frustration",
    "Curiosity",
    "Amusement",
    "Boredom",
    "Loneliness",
    "Empathy",
    "Sympathy",
    "Anticipation",
    "Disappointment",
    "Relief",
    "Nostalgia",
    "Awe",
    "Eagerness",
    "Confidence",
    "Insecurity",
    "Embarrassment",
    "Indifference",
    "Confusion",
    "Admiration",
    "Compassion",
    "Resentment",
    "Calmness",
    "Apprehension",
    "Sorrow",
    "Contempt",
    "Irritation",
    "Melancholy",
    "Bliss",
    "Regret",
    "Satisfaction",
    "Yearning",
    "Serenity"
]

Next, I will use edsl as I did previously. In this case, I will give each agent an emotional state via the persona specification that edsl supports.

from edsl.agents import Agent
from edsl.questions import QuestionFreeText

emotion_string = "You are currently experiencing the emotion {emotion}"

agents = [Agent(traits = {'persona':emotion_string.format(emotion=e.lower())}) for e in emotions]

q = QuestionFreeText(
    question_name = "favorite_color",
    question_text = "What is the color that best represents how you are feeling right now? Respond with only an RGB code in the form (R,G,B) where each value is between 0 and 255."
)

result = q.by(agents).run()

Now I extract all the emotions and colors into a set of tuples:

import ast 
tups = list(zip([e.lower() for e in emotions], [ast.literal_eval(r.answer['favorite_color']) for r in result]))

Great, so now we have a list of emotions and colors. First, let’s look at the raw results. Using chatgpt I write a function to convert my list of tuples into a table:

def generate_html_table(emotion_colors):
    # Starting the HTML for the table
    html = "<table border='1'>"

    # Adding headers
    html += "<tr><th>Emotion</th><th>RGB Value</th><th>Color</th></tr>"

    # Iterating over the list of tuples to fill the rows
    for emotion, color in emotion_colors:
        # Format the RGB color as a string
        color_rgb_string = f"({color[0]}, {color[1]}, {color[2]})"
        # Format the RGB color for HTML styling
        color_rgb_html = f"rgb{color}"
        # Adding a row with the emotion, the RGB string, and a colored cell
        html += f"<tr><td>{emotion}</td><td>{color_rgb_string}</td><td style='background-color: {color_rgb_html};'></td></tr>"

    # Closing the table tag
    html += "</table>"

    return html

Here is the table that results:

EmotionRGB ValueColor
happiness(255, 255, 0)
sadness(0, 0, 255)
anger(255, 0, 0)
fear(0, 0, 0)
disgust(128, 0, 0)
surprise(255, 215, 0)
love(255, 0, 0)
joy(255, 255, 0)
anxiety(255, 165, 0)
excitement(255, 165, 0)
jealousy(255, 0, 0)
gratitude(173, 216, 230)
contentment(0, 128, 0)
hope(0, 255, 0)
pride(0, 255, 0)
shame(255, 0, 0)
guilt(128, 0, 0)
envy(0, 128, 0)
frustration(255, 0, 0)
curiosity(0, 128, 255)
amusement(255, 255, 0)
boredom(105, 105, 105)
loneliness(0, 0, 0)
empathy(255, 191, 0)
sympathy(0, 0, 255)
anticipation(255, 165, 0)
disappointment(70, 130, 180)
relief(0, 255, 0)
nostalgia(255, 211, 0)
awe(0, 255, 255)
eagerness(255, 165, 0)
confidence(0, 128, 0)
insecurity(255, 165, 0)
embarrassment(255, 0, 0)
indifference(128, 128, 128)
confusion(128, 128, 128)
admiration(0, 255, 0)
compassion(255, 102, 102)
resentment(255, 0, 0)
calmness(0, 128, 0)
apprehension(255, 165, 0)
sorrow(0, 0, 0)
contempt(0, 255, 0)
irritation(255, 69, 0)
melancholy(70, 89, 119)
bliss(0, 255, 0)
regret(128, 0, 0)
satisfaction(0, 255, 0)
yearning(255, 204, 0)
serenity(0, 176, 240)

To be honest, I’m not super impressed with gpt3.5’s work here. Among other tthings, there is a disappointing amount of color-reuse across distinct emotions. I wonder what happens if I try prompting GPT4 instead? Let’s try re-running with that via edsl. I think that’s as simple as:

m4 = Model('gpt-4-1106-preview', cache=False)
result4 = q.by(agents).by(m4).run()
tups4 = list(zip([e.lower() for e in emotions], [ast.literal_eval(r.answer['favorite_color']) for r in result4]))

Here are the new results:

EmotionRGB ValueColor
happiness(255, 223, 0)
sadness(105, 105, 105)
anger(255, 0, 0)
fear(0, 0, 0)
disgust(96, 123, 139)
surprise(255, 255, 0)
love(255, 105, 180)
joy(255, 223, 0)
anxiety(128, 123, 104)
excitement(255, 215, 0)
jealousy(102, 204, 0)
gratitude(255, 184, 108)
contentment(173, 216, 230)
hope(255, 223, 0)
pride(255, 215, 0)
shame(245, 245, 220)
guilt(128, 128, 128)
envy(76, 187, 23)
frustration(255, 0, 0)
curiosity(255, 165, 0)
amusement(255, 133, 27)
boredom(128, 128, 128)
loneliness(105, 105, 105)
empathy(79, 91, 213)
sympathy(255, 192, 203)
anticipation(255, 165, 0)
disappointment(105, 105, 105)
relief(135, 206, 250)
nostalgia(255, 192, 203)
awe(255, 215, 0)
eagerness(255, 165, 0)
confidence(255, 215, 0)
insecurity(128, 128, 128)
embarrassment(249, 132, 229)
indifference(128, 128, 128)
confusion(128, 128, 128)
admiration(255, 223, 0)
compassion(255, 105, 180)
resentment(153, 76, 0)
calmness(135, 206, 250)
apprehension(128, 128, 128)
sorrow(105, 105, 105)
contempt(64, 64, 72)
irritation(255, 0, 0)
melancholy(105, 105, 105)
bliss(135, 206, 250)
regret(105, 105, 105)
satisfaction(76, 175, 80)
yearning(72, 61, 139)
serenity(135, 206, 250)

This feels a bit richer, intuitively, though still includes a lot of repetitions. To see this more clearly, here’s a version of the table sorting by brightness:

def generate_html_table(emotion_colors):
    # Function to calculate the average brightness of an RGB color
    def calculate_brightness(rgb):
        return sum(rgb) / len(rgb)

    # Sorting the emotion_colors list by the average brightness of the colors
    sorted_emotion_colors = sorted(emotion_colors, key=lambda x: calculate_brightness(x[1]), reverse=True)

    # Starting the HTML for the table
    html = "<table border='1'>"

    # Adding headers
    html += "<tr><th>Emotion</th><th>RGB Value</th><th>Color</th></tr>"

    # Iterating over the sorted list of tuples to fill the rows
    for emotion, color in sorted_emotion_colors:
        # Format the RGB color as a string
        color_rgb_string = f"({color[0]}, {color[1]}, {color[2]})"
        # Format the RGB color for HTML styling
        color_rgb_html = f"rgb{color}"
        # Adding a row with the emotion, the RGB string, and a colored cell
        html += f"<tr><td>{emotion}</td><td>{color_rgb_string}</td><td style='background-color: {color_rgb_html};'></td></tr>"

    # Closing the table tag
    html += "</table>"

    return html
EmotionRGB ValueColor
shame(245, 245, 220)
sympathy(255, 192, 203)
nostalgia(255, 192, 203)
contentment(173, 216, 230)
embarrassment(249, 132, 229)
relief(135, 206, 250)
calmness(135, 206, 250)
bliss(135, 206, 250)
serenity(135, 206, 250)
gratitude(255, 184, 108)
love(255, 105, 180)
compassion(255, 105, 180)
surprise(255, 255, 0)
happiness(255, 223, 0)
joy(255, 223, 0)
hope(255, 223, 0)
admiration(255, 223, 0)
excitement(255, 215, 0)
pride(255, 215, 0)
awe(255, 215, 0)
confidence(255, 215, 0)
curiosity(255, 165, 0)
anticipation(255, 165, 0)
eagerness(255, 165, 0)
amusement(255, 133, 27)
guilt(128, 128, 128)
boredom(128, 128, 128)
insecurity(128, 128, 128)
indifference(128, 128, 128)
confusion(128, 128, 128)
apprehension(128, 128, 128)
empathy(79, 91, 213)
disgust(96, 123, 139)
anxiety(128, 123, 104)
satisfaction(76, 175, 80)
sadness(105, 105, 105)
loneliness(105, 105, 105)
disappointment(105, 105, 105)
sorrow(105, 105, 105)
melancholy(105, 105, 105)
regret(105, 105, 105)
jealousy(102, 204, 0)
envy(76, 187, 23)
yearning(72, 61, 139)
anger(255, 0, 0)
frustration(255, 0, 0)
irritation(255, 0, 0)
resentment(153, 76, 0)
contempt(64, 64, 72)
fear(0, 0, 0)

Interesting. Here we can better see the color repetition. There seem to be clear nodes around (1) a shade of light blue that’s assosciated with calmness/relief etc, (2) a shade of warm yellow/gold that’s associated with positive emotions (happiness, joy, awe, confidence), (3) a shade of lighter gray associated with neutral/negative emotions (guilt, boredom, indifference), (4)a shade of darker grey associated with more negative emotions (sadness, loneliness, regret), and (5) bright red for anger/frustration/irritation. There’s a few other more unique and intuitive picks like green for jealousy/envy and black for fear. Shame at the top as an off-white is somewhat surprising to me.

I do notice that there seems to be a generally positive association between brightness (average RGB value) and the extent of “positivity” of the emotion, with the exception of shame, sympathy and nostalgia at the very top.

In general, it’s also interesting that the set of colors are so different compared to GPT3.5 which is the default that was used above. I’m also curious how much results would differ with tweaks to the prompts (e.g. even just asking for hex codes or CMYK colors instead of RGB).

There’s various further analysis we could do here – e.g. I considered doing a 2D embedding with t-SNE and visualizing the results. I’ll save that for another day. My main goal here was just to experiment a bit more with edsl and get familiar.