1
1
import matplotlib as mpl
2
2
import numpy as np
3
+ import webcolors
4
+
5
+ # RGB values (as taken from xcolor.dtx):
6
+ builtin_colors = {
7
+ "white" : [1 , 1 , 1 ],
8
+ "lightgray" : [0.75 , 0.75 , 0.75 ],
9
+ "gray" : [0.5 , 0.5 , 0.5 ],
10
+ "darkgray" : [0.25 , 0.25 , 0.25 ],
11
+ "black" : [0 , 0 , 0 ],
12
+ #
13
+ "red" : [1 , 0 , 0 ],
14
+ "green" : [0 , 1 , 0 ],
15
+ "blue" : [0 , 0 , 1 ],
16
+ "brown" : [0.75 , 0.5 , 0.25 ],
17
+ "lime" : [0.75 , 1 , 0 ],
18
+ "orange" : [1 , 0.5 , 0 ],
19
+ "pink" : [1 , 0.75 , 0.75 ],
20
+ "purple" : [0.75 , 0 , 0.25 ],
21
+ "teal" : [0 , 0.5 , 0.5 ],
22
+ "violet" : [0.5 , 0 , 0.5 ],
23
+ # The colors cyan, magenta, yellow, and olive are also
24
+ # predefined by xcolor, but their RGB approximation of the
25
+ # native CMYK values is not very good. Don't use them here.
26
+ }
27
+
28
+
29
+ def _get_closest_colour_name (rgb ):
30
+ match = None
31
+ mindiff = 1.0e15
32
+ for h , name in webcolors .CSS3_HEX_TO_NAMES .items ():
33
+ r = int (h [1 :3 ], 16 )
34
+ g = int (h [3 :5 ], 16 )
35
+ b = int (h [5 :7 ], 16 )
36
+
37
+ diff = (rgb [0 ] - r ) ** 2 + (rgb [1 ] - g ) ** 2 + (rgb [2 ] - b ) ** 2
38
+ if diff < mindiff :
39
+ match = name
40
+ mindiff = diff
41
+
42
+ if mindiff == 0 :
43
+ break
44
+
45
+ return match , mindiff
3
46
4
47
5
48
def mpl_color2xcolor (data , matplotlib_color ):
@@ -12,66 +55,30 @@ def mpl_color2xcolor(data, matplotlib_color):
12
55
if my_col [- 1 ] == 0.0 :
13
56
return data , "none" , my_col
14
57
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
-
44
58
# Check if it exactly matches any of the colors already available.
45
59
# This case is actually treated below (alpha==1), but that loop
46
60
# may pick up combinations with black before finding the exact
47
61
# match. Hence, first check all colors.
48
- for name , rgb in available_colors .items ():
62
+ for name , rgb in builtin_colors .items ():
49
63
if all (my_col [:3 ] == rgb ):
50
- xcol = name
51
- return data , xcol , my_col
64
+ return data , name , my_col
52
65
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
66
+ # Don't handle gray colors separately. They can be specified in xcolor as
67
+ #
68
+ # {gray}{0.6901960784313725}
69
+ #
70
+ # but this float representation hides the fact that this is actually an
71
+ # RGB255 integer value, 176.
57
72
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 ]
73
+ # convert to RGB255
74
+ rgb255 = np .array (my_col [:3 ] * 255 , dtype = int )
65
75
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
72
-
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 ]
76
+ name , diff = _get_closest_colour_name (rgb255 )
77
+ if diff > 0 :
78
+ if np .all (my_col [0 ] == my_col [:3 ]):
79
+ name = f"{ name } { rgb255 [0 ]} "
80
+ else :
81
+ name = f"{ name } { rgb255 [0 ]} { rgb255 [1 ]} { rgb255 [2 ]} "
82
+ data ["custom colors" ][name ] = ("RGB" , "," .join ([str (val ) for val in rgb255 ]))
76
83
77
- return data , xcol , my_col
84
+ return data , name , my_col
0 commit comments