11import matplotlib as mpl
22import numpy as np
3+ import webcolors
4+
5+ # RGB values (as taken from xcolor.dtx):
6+ builtin_colors = {
7+ # List white first such that for gray values, the combination
8+ # white!<x>!black is preferred over, e.g., gray!<y>!black. Note that
9+ # the order of the dictionary is respected from Python 3.6 on.
10+ "white" : np .array ([1 , 1 , 1 ]),
11+ "lightgray" : np .array ([0.75 , 0.75 , 0.75 ]),
12+ "gray" : np .array ([0.5 , 0.5 , 0.5 ]),
13+ "darkgray" : np .array ([0.25 , 0.25 , 0.25 ]),
14+ "black" : np .array ([0 , 0 , 0 ]),
15+ #
16+ "red" : np .array ([1 , 0 , 0 ]),
17+ "green" : np .array ([0 , 1 , 0 ]),
18+ "blue" : np .array ([0 , 0 , 1 ]),
19+ "brown" : np .array ([0.75 , 0.5 , 0.25 ]),
20+ "lime" : np .array ([0.75 , 1 , 0 ]),
21+ "orange" : np .array ([1 , 0.5 , 0 ]),
22+ "pink" : np .array ([1 , 0.75 , 0.75 ]),
23+ "purple" : np .array ([0.75 , 0 , 0.25 ]),
24+ "teal" : np .array ([0 , 0.5 , 0.5 ]),
25+ "violet" : np .array ([0.5 , 0 , 0.5 ]),
26+ # The colors cyan, magenta, yellow, and olive are also
27+ # predefined by xcolor, but their RGB approximation of the
28+ # native CMYK values is not very good. Don't use them here.
29+ }
30+
31+
32+ def _get_closest_colour_name (rgb ):
33+ match = None
34+ mindiff = 1.0e15
35+ for h , name in webcolors .CSS3_HEX_TO_NAMES .items ():
36+ r = int (h [1 :3 ], 16 )
37+ g = int (h [3 :5 ], 16 )
38+ b = int (h [5 :7 ], 16 )
39+
40+ diff = (rgb [0 ] - r ) ** 2 + (rgb [1 ] - g ) ** 2 + (rgb [2 ] - b ) ** 2
41+ if diff < mindiff :
42+ match = name
43+ mindiff = diff
44+
45+ if mindiff == 0 :
46+ break
47+
48+ return match , mindiff
349
450
551def mpl_color2xcolor (data , matplotlib_color ):
@@ -12,66 +58,28 @@ def mpl_color2xcolor(data, matplotlib_color):
1258 if my_col [- 1 ] == 0.0 :
1359 return data , "none" , my_col
1460
15- xcol = None
16- # RGB values (as taken from xcolor.dtx):
17- available_colors = {
18- # List white first such that for gray values, the combination
19- # white!<x>!black is preferred over, e.g., gray!<y>!black. Note that
20- # the order of the dictionary is respected from Python 3.6 on.
21- "white" : np .array ([1 , 1 , 1 ]),
22- "lightgray" : np .array ([0.75 , 0.75 , 0.75 ]),
23- "gray" : np .array ([0.5 , 0.5 , 0.5 ]),
24- "darkgray" : np .array ([0.25 , 0.25 , 0.25 ]),
25- "black" : np .array ([0 , 0 , 0 ]),
26- #
27- "red" : np .array ([1 , 0 , 0 ]),
28- "green" : np .array ([0 , 1 , 0 ]),
29- "blue" : np .array ([0 , 0 , 1 ]),
30- "brown" : np .array ([0.75 , 0.5 , 0.25 ]),
31- "lime" : np .array ([0.75 , 1 , 0 ]),
32- "orange" : np .array ([1 , 0.5 , 0 ]),
33- "pink" : np .array ([1 , 0.75 , 0.75 ]),
34- "purple" : np .array ([0.75 , 0 , 0.25 ]),
35- "teal" : np .array ([0 , 0.5 , 0.5 ]),
36- "violet" : np .array ([0.5 , 0 , 0.5 ]),
37- # The colors cyan, magenta, yellow, and olive are also
38- # predefined by xcolor, but their RGB approximation of the
39- # native CMYK values is not very good. Don't use them here.
40- }
41-
42- available_colors .update (data ["custom colors" ])
43-
4461 # Check if it exactly matches any of the colors already available.
4562 # This case is actually treated below (alpha==1), but that loop
4663 # may pick up combinations with black before finding the exact
4764 # match. Hence, first check all colors.
48- for name , rgb in available_colors .items ():
65+ for name , rgb in builtin_colors .items ():
4966 if all (my_col [:3 ] == rgb ):
50- xcol = name
51- return data , xcol , my_col
52-
53- # Check if my_col is a multiple of a predefined color and 'black'.
54- for name , rgb in available_colors .items ():
55- if name == "black" :
56- continue
67+ return data , name , my_col
5768
58- if rgb [0 ] != 0.0 :
59- alpha = my_col [ 0 ] / rgb [ 0 ]
60- elif rgb [ 1 ] ! = 0.0 :
61- alpha = my_col [1 ] / rgb [ 1 ]
62- else :
63- assert rgb [ 2 ] != 0.0
64- alpha = my_col [ 2 ] / rgb [ 2 ]
69+ if np . all ( my_col [0 ] == my_col [: 3 ]) :
70+ # gray
71+ # my_col[0] = 0.70123112 -> gray070
72+ name = f"gray { int ( 100 * my_col [0 ]):03d } "
73+ if name not in data [ "custom colors" ] :
74+ data [ "custom colors" ][ name ] = ( "gray" , str ( my_col [ 0 ]))
75+ return data , name , my_col
6576
66- # The cases 0.0 (my_col == black) and 1.0 (my_col == rgb) are
67- # already accounted for by checking in available_colors above.
68- if all (my_col [:3 ] == alpha * rgb ) and 0.0 < alpha < 1.0 :
69- ff = data ["float format" ]
70- xcol = name + f"!{ alpha * 100 :{ff }} !black"
71- return data , xcol , my_col
77+ # convert to RGB255
78+ rgb255 = np .array (my_col [:3 ] * 255 , dtype = int )
7279
73- # Lookup failed, add it to the custom list.
74- xcol = "color" + str (len (data ["custom colors" ]))
75- data ["custom colors" ][xcol ] = my_col [:3 ]
80+ name , diff = _get_closest_colour_name (rgb255 )
81+ if diff > 0 :
82+ name = f"{ name } { rgb255 [0 ]} { rgb255 [1 ]} { rgb255 [2 ]} "
83+ data ["custom colors" ][name ] = ("RGB" , "," .join ([str (val ) for val in rgb255 ]))
7684
77- return data , xcol , my_col
85+ return data , name , my_col
0 commit comments