Material io color palette complementary - colors

I'm using the colors related to the Material io palettes, link palette
The colors are as follows:
'red',
'pink',
'purple',
'deepPurple',
'indigo',
'blue',
'lightBlue',
'cyan',
'teal',
'green',
'lightGreen',
'lime',
'yellow',
'amber',
'orange',
'deepOrange',
'brown',
'grey',
'blueGrey'
The colors in total are 19, of which only 16 have as definition as shade also A100, A200, A400, A700.
For each color I would like to define its complementary.
But I'm having some doubts about it.
For example:
Red, its complementary is green.
Pink, its complementary green.
So green is the complement of two colors, so it has two complementaries?
[
{red: ['green']},
{pink: ['green']},
{green: ['red','pink']}
]
Can you tell me where I can find some more information?
But if I take the red 500, it tells me according to material io, that the complementary is the lightBlue 200.
So I'm having doubts.

Complementary color can be calculated like this
first definition:
change color to hexadecimal number (red = 0xff0000)
complementary color = 0xffffff - color(0xff0000)
second definition :
change color to HSL(hue, saturation, lightness)
change hue to opposite : (hue + 180) % 360

Related

How to assign a specific color to a specific set of values when generating a heatmap when using sns.heatmap?

In a project, I am attempting to assign colors to specific value ranges when plotting a heatmap using sns.heatmap. The goal is to get all values between 0-50 colored green, 50-100 colored yellow, 100-150 colored orange, 150-200 colored red, and 200 and above colored purple. Here is what has been tried so far:
# To create a custom color palette for the heatmap.
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
def create_color(r, g, b):
return [r/256, g/256, b/256]
# RGB codes for green, yellow, orange, red, purple, respectively
def my_colors():
return LinearSegmentedColormap.from_list("", [
create_color(0, 255, 0), create_color(255,255,0), create_color(255,165,0),
create_color(255, 0, 0), create_color(143,0,255)])
# creating a colormap
colormap = my_colors()
#defining "plt"
import matplotlib.pyplot as plt
# Figure plotting
fig = plt.figure(figsize=(12,12))
# Plot heatmap with 'cmap=colormap' colors.
r = sns.heatmap(data, cmap=colormap, annot=True, vmin=0, vmax=200, linewidths=0.5, cbar_kws={"shrink": 0.8},
palette={'Value' <= 50:'(0, 255, 0)',
51 <= 'Value' <=100:'(255, 255, 0)',
101 <= 'Value' <= 150:'(255,165,0)',
151 <= 'Value' <= 200:'(255, 0, 0)',
201 <= 'Value' <= 300:'(143,0,255)',
301 <= 'Value' <= 500:'(128,0,0)'})
plt.xlabel('x')
plt.ylabel('y')
r.set_title("Heatmap")
However, <= cannot be used to relate a str and an int. Any idea how to assign one color to a range of values in this way? or is there an easier way?

Converting IntegerRGB to sRGB

I am trying to use the following code to calculate the delta_e.
from colormath.color_objects import sRGBColor, LabColor
from colormath.color_conversions import convert_color
from colormath.color_diff import delta_e_cie2000
# Red Color
color1_rgb = sRGBColor(1.0, 0.0, 0.0);
# Blue Color
color2_rgb = sRGBColor(0.0, 0.0, 1.0);
# Convert from RGB to Lab Color Space
color1_lab = convert_color(color1_rgb, LabColor);
# Convert from RGB to Lab Color Space
color2_lab = convert_color(color2_rgb, LabColor);
# Find the color difference
delta_e = delta_e_cie2000(color1_lab, color2_lab);
print "The difference between the 2 color = ", delta_e
However, the input that I have is the name of the color, such as 'Black', 'White', 'Red', etc. I originally thought of using webcolours.name_to_rgb to convert the name to the RGB format, but this gives me IntegerRGB and not sRGB that I would need. How should I go about converting them from IntegerRGB to sRGB? Alternatively, is it possible to get the sRGB from the name directly? Many thanks!

Misunderstanding in a Matplotlib program

I was working on the code "Discrete distribution as horizontal bar chart", found here LINK, using Matplotlib 3.1.1
I've been circling around the question for a while, but I still can't figure it out: what's the meaning of the instruction: category_colors = plt.get_cmap('RdYlGn')(np.linspace(0.15, 0.85, data.shape[1])) ?
As np.linspace(0.15, 0.85, data.shape[1]) resolves to array([0.15 , 0.325, 0.5 , 0.675, 0.85 ]), I first thought that the program was using the colormap RdYlGn (supposed to go from color=0.0 to color=1.0) and was then taking the 5 specific colors located at point 0.15, etc., 0.85
But, printing category_colors resolves to a (5, 4) array:
array([[0.89888504, 0.30549789, 0.20676663, 1. ],
[0.99315648, 0.73233372, 0.42237601, 1. ],
[0.99707805, 0.9987697 , 0.74502115, 1. ],
[0.70196078, 0.87297193, 0.44867359, 1. ],
[0.24805844, 0.66720492, 0.3502499 , 1. ]])
I don't understand what these numbers refer to ???
plt.get_cmap('RdYlGn') returns a function which maps a number between 0 and 1 to a corresponding color, where 0 gets mapped to red, 0.5 to yellow and 1 to green. Often, this function gets the name cmap = plt.get_cmap('RdYlGn'). Then cmap(0) (which is the same as plt.get_cmap('RdYlGn')(0)) would be the rbga-value (0.6470588235294118, 0.0, 0.14901960784313725, 1.0) for (red, green, blue, alpha). In hexadecimal, this color would be #a50026.
By numpy's broadcasting magic, cmap(np.array([0.15 , 0.325, 0.5 , 0.675, 0.85 ])) gets the same result as np.array([cmap(0.15), cmap(0.325), ..., cmap(0.85)]). (In other words, many numpy functions applied to an array return an array of that function applied to the individual elements.)
So, the first row of category_colors = cmap(np.linspace(0.15, 0.85, 5)) will be the rgba-values of the color corresponding to value 0.15, or 0.89888504, 0.30549789, 0.20676663, 1.. This is a color with 90% red, 31% green and 21% blue (and alpha=1 for complete opaque), so quite reddish. The next row are the rgba values corresponding to 0.325, and so on.
Here is some code to illustrate the concepts:
import matplotlib.pyplot as plt
from matplotlib.colors import to_hex # convert a color to hexadecimal format
from matplotlib.cm import ScalarMappable # needed to create a custom colorbar
import numpy as np
cmap = plt.get_cmap('RdYlGn')
color_values = np.linspace(0.15, 0.85, 5)
category_colors = cmap(color_values)
plt.barh(color_values, 1, height=0.15, color=category_colors)
plt.yticks(color_values)
plt.colorbar(ScalarMappable(cmap=cmap), ticks=color_values)
plt.ylim(0, 1)
plt.xlim(0, 1.1)
plt.xticks([])
for val, color in zip(color_values, category_colors):
r, g, b, a = color
plt.text(0.1, val, f'r:{r:0.2f} g:{g:0.2f} b:{b:0.2f} a:{a:0.1f}\nhex:{to_hex(color)}', va='center')
plt.show()
PS: You might also want to read about norms, which map an arbitrary range to the range 0,1 to be used by colormaps.

How to apply a linestyle to a specific line in Seaborn lineplot?

I have the a dataframe where in the column Products there are many different items, let's show only a few:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
data = np.array([[1, 1, 570], [2, 1, 650], [1, 2, 27], [2, 2, 64], [1, 3, 125], [2, 3, 216],
[1, 'item_1', 343], [2, 'item_1', 340], [1, 'item_2', 343], [2, 'item_2', 345]])
df = pd.DataFrame(data=data, columns=["Flag", "Products", "Value"])
I'm using Seaborn to get the following lineplot:
sns.set_theme()
sns.set_style("ticks")
sns.set_context("paper")
fig1, ax1 = plt.subplots()
sns.lineplot(data=df, x="Flag", y="Value",
hue="Products", style="Products", ax=ax1)
plt.legend(bbox_to_anchor=(1.02, 1),borderaxespad=0)
fig1.tight_layout()
In this way all the lines have a style "chosen" by Seaborn, but I need to set a specific color and a line style (not dashed) for the products named 'item_1' and 'item_2'.
Up to now I have found the following solution:
palette = {c:'red' if c=='item_1' else 'blue' for c in df.Products.unique()}
sns.lineplot(data=df, x="Flag", y="Value",
hue="Products", style="Products", palette=palette, ax=ax1)
So, I can set the red color for the item_1 only, but all the other lines are blue, while I'd like to:
set the red color and not-dashed lines for both items_1 and items_2
set another color palette (e.g. bright) for all the other lines
Is it possible to do that?
palette= and dashes= can be passed a dictionary mapping levels of the column used to different colors/styles.
You can generate these dictionaries by hand or programmatically (depending on how many levels you have).
for instance, the color palette:
#color palette
cmap = sns.color_palette("bright")
palette = {key:value for key,value in zip(data[hue_col].unique(), cmap)}
palette['item_1'] = 'red'
palette['item_2'] = 'red'
output:
{'1': (0.00784313725490196, 0.24313725490196078, 1.0),
'2': (1.0, 0.48627450980392156, 0.0),
'3': (0.10196078431372549, 0.788235294117647, 0.2196078431372549),
'item_1': 'red,
'item_2': 'red'}
we give each level a different color from the "bright" palette, and we can fix some values by hand if needed (although do keep in mind that there is a color very similar to red in the bright palette already, so there might be some possible confusion).
The same can be done for the dash style:
#style palette
dash_list = sns._core.unique_dashes(data[style_col].unique().size+1)
style = {key:value for key,value in zip(data[style_col].unique(), dash_list[1:])}
style['item_1'] = '' # empty string means solid
style['item_2'] = ''
output:
{'1': (4, 1.5),
'2': (1, 1),
'3': (3, 1.25, 1.5, 1.25),
'item_1': '',
'item_2': ''}
Here I use one of seaborn's private functions (use at your own risk, could change at any time), to generate a list of dash styles, and then manually set the particular levels I want to have a solid line. I request one too many items in dash_list because the first element is always a solid line, and I want to reserve solid lines for item_1 and item_2.
full code:
data = df
x_col = 'Flag'
y_col = "Value"
hue_col = "Products"
style_col = "Products"
#color palette
cmap = sns.color_palette("bright")
palette = {key:value for key,value in zip(data[hue_col].unique(), cmap)}
palette['item_1'] = 'red'
palette['item_2'] = 'red'
#style palette
dash_list = sns._core.unique_dashes(data[style_col].unique().size+1)
style = {key:value for key,value in zip(data[style_col].unique(), dash_list[1:])}
style['item_1'] = '' # empty string means solid
style['item_2'] = ''
sns.set_theme()
sns.set_style("ticks")
sns.set_context("paper")
fig1, ax1 = plt.subplots()
sns.lineplot(data=df, x=x_col, y=y_col,
hue=hue_col, palette=palette,
style=style_col, dashes=style,
ax=ax1)
plt.legend(bbox_to_anchor=(1.02, 1),borderaxespad=0)
fig1.tight_layout()
Thanks a lot #Diziet Asahi, indeed this works in the example dataframe! But, in my full dataframe that contains many more items I get the error message:
The palette dictionary is missing keys: {'9', '20', ...}
I guess that this is due to the fact that the default color palette in seaborn is a qualitative palette with ten distinct hues only.
To handle this error I set the following color palette:
cmap = sns.color_palette("hls", 75)
This works also choosing the "husl" color space.

Get RGB from Hue (S & L would be 100)

I need to get the RGB of a HSL with the SL both max. (get RGB from 125, 100, 100)
So, just the hue is changing.
Is there a simple formula for this?
Thanks
See Converting to RGB towards the end of http://en.wikipedia.org/wiki/HSL_and_HSV
In HSL color mode, if L = 100, then S = 0 and H = undefined.
Yes theres a formula. RGB = (255, 255, 255). When L is 100 (max), then your R,G,B is maxed (ie white), no matter what the Hue, or even Saturation.

Resources