Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to match a string to a random color matplotlib

I want to translate the labels of some data to colors for graphing with matplotlib

I have a list of names ["bob", "joe", "andrew", "pete"]

Is there a built in way to map these strings with color values in matplotlib? I thought about randomly creating hex values but I could end up with similar colors or non visible colors.

I've tried a couple different ways of trying to create key values from the below cmap answer:

this:

#names is a list of distinct names
cmap = plt.get_cmap('cool')
colors = cmap(np.linspace(0, 1, len(names)))
clr = {names[i]: colors[i] for i in range(len(names))}
ax.scatter(x, y, z, c=clr)
like image 702
ford prefect Avatar asked Aug 07 '15 17:08

ford prefect


People also ask

How do I select a random color in matplotlib?

To make a custom color, we can create a hexadecimal string. From it, we can make different sets of color representation and can pass into the scatter method to get the desired output.

How do you randomize colors in python?

Using random() function to generate random colors To begin, import the random function in Python to obtain a random color. The variable r stands for red, g stands for green, and b stands for blue. We already know that the RGB format contains an integer value ranging from 0 to 255.


2 Answers

Choose a color map, such as viridis:

cmap = plt.get_cmap('viridis')

The colormap, cmap, is a function which can take an array of values from 0 to 1 and map them to RGBA colors. np.linspace(0, 1, len(names)) produces an array of equally spaced numbers from 0 to 1 of length len(names). Thus,

colors = cmap(np.linspace(0, 1, len(names)))

selects equally-spaced colors from the viridis color map.

Note that this is not using the value of the string, it only uses the ordinal position of the string in the list to select a color. Note also that these are not random colors, this is just an easy way to generate unique colors from an arbitrary list of strings.


So:

import numpy as np
import matplotlib.pyplot as plt

cmap = plt.get_cmap('viridis')
names = ["bob", "joe", "andrew", "pete"]
colors = cmap(np.linspace(0, 1, len(names)))
print(colors)
# [[ 0.267004  0.004874  0.329415  1.      ]
#  [ 0.190631  0.407061  0.556089  1.      ]
#  [ 0.20803   0.718701  0.472873  1.      ]
#  [ 0.993248  0.906157  0.143936  1.      ]]

x = np.linspace(0, np.pi*2, 100)
for i, (name, color) in enumerate(zip(names, colors), 1):
    plt.plot(x, np.sin(x)/i, label=name, c=color)
plt.legend()
plt.show()

enter image description here


The problem with

clr = {names[i]: colors[i] for i in range(len(names))}
ax.scatter(x, y, z, c=clr)

is that the c parameter of ax.scatter expects a sequence of RGB(A) values of the same length as x or a single color. clr is a dict, not a sequence. So if colors is the same length as x then you could use

ax.scatter(x, y, z, c=colors)
like image 174
unutbu Avatar answered Oct 23 '22 09:10

unutbu


I use the hash function to get numbers between 0 and 1, you can use this even when you don't know all the labels:

x = [1, 2, 3, 4, 5]
labels = ["a", "a", "b", "b", "a"]
y = [1, 2, 3, 4, 5]

colors = [float(hash(s) % 256) / 256 for s in labels]      

plt.scatter(x, y, c=colors, cmap="jet")
plt.show()
like image 29
pomber Avatar answered Oct 23 '22 10:10

pomber