1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 """
21 Various functions for handling colors. Used mainly for visualizing output
22 of plugins with heatmaps (for now).
23
24 Most of the code below is made to match this color chart:
25 http://en.wikipedia.org/wiki/File:Xterm_256color_chart.svg
26
27 The colorspace conversions are thin wrappers around colorsys, except for
28 the code to handle XTerm colors, which is my own work.
29 """
30 __author__ = "Adam Sindelar <adamsh@google.com>"
31
32 import colorsys
33
34
36 for step, ceiling in enumerate(steps):
37 if int(value) <= ceiling:
38 return step
39
40 raise ValueError("Maximum value of %d exceeded with %d." % (steps[-1],
41 value))
42
43
44 XTERM16 = ((0x00, 0x00, 0x00), (0x80, 0x00, 0x00), (0x00, 0x80, 0x00),
45 (0x80, 0x80, 0x00), (0x00, 0x00, 0x80), (0x80, 0x00, 0x80),
46 (0x00, 0x80, 0x80), (0xc0, 0xc0, 0xc0), (0x80, 0x80, 0x80),
47 (0xff, 0x00, 0x00), (0x00, 0xff, 0x00), (0xff, 0xff, 0x00),
48 (0x00, 0x00, 0xff), (0xff, 0x00, 0xff), (0x00, 0xff, 0xff),
49 (0xff, 0xff, 0xff))
50 """XTerm has 16 special colors, as listed above."""
51
52
53 XTERM_CHANNEL_STEPS = [0, 0x5f, 0x87, 0xaf, 0xd7, 0xff]
54 """XTerm color space is sparse at low luminosity."""
55
56
59
60
63
64
65
66
67
89
90
92 """Convert the XTerm color (0-255) to an RGB equivalent."""
93 if xterm < 16:
94 return XTERM16[xterm]
95
96 if xterm >= 232:
97
98 value = (xterm - 231) * 0x08
99 return value, value, value
100
101 xterm -= 16
102 red, r = divmod(xterm, 6 ** 2)
103 green, blue = divmod(r, 6)
104
105 return (XTERM_CHANNEL_STEPS[red],
106 XTERM_CHANNEL_STEPS[green],
107 XTERM_CHANNEL_STEPS[blue])
108
109
111 hue, luminosity, saturation = colorsys.rgb_to_hls(
112 float(red) / 0xff, float(green) / 0xff, float(blue) / 0xff)
113
114 return hue, saturation, luminosity
115
116
118 return colorsys.rgb_to_yiq(
119 float(red) / 0xff, float(green) / 0xff, float(blue) / 0xff)
120
121
122 -def HSLToRGB(hue, saturation, luminosity):
123 red, green, blue = colorsys.hls_to_rgb(hue, luminosity, saturation)
124 return int(red * 0xff), int(green * 0xff), int(blue * 0xff)
125
126
128 red, green, blue = colorsys.yiq_to_rgb(y, i, q)
129 return int(red * 0xff), int(green * 0xff), int(blue * 0xff)
130
131
132
133
134
136 """Compute the foreground color, given the background color."""
137
138
139
140
141
142
143
144
145
146 return (0, 0, 0) if (y * 2 - i - q) > .8 else (1, 0, 0)
147
148
149 -def RGBTextForBackground(red, green, blue):
150 """Compute the foreground color, given the background color."""
151 hsl = RGBToYIQ(red, green, blue)
152 text = YIQTextForBackground(*hsl)
153 r, g, b = YIQToRGB(*text)
154 return r, g, b
155
156
158 """Compute the foreground color, given the background color."""
159 rgb = XTermToRGB(xterm)
160 fg = RGBTextForBackground(*rgb)
161 return RGBToXTerm(*fg)
162
163
164
165
166
168 """Blend RGB colors x and y, optionally using assigned weights wx and wy."""
169 t = wx + wy
170 return ((x[0] * wx + y[0] * wy) / t,
171 (x[1] * wx + y[1] * wy) / t,
172 (x[2] * wx + y[2] * wy) / t)
173
174
176 """Given heat (0-1.0), compute the color to represent it on a heatmap.
177
178 Arguments:
179 Greyscale: If True, use luminosity instead of hue.
180 """
181 if greyscale:
182 saturation = 0
183 hue = 0
184 luminosity = heat
185 else:
186 saturation = 1.0
187 luminosity = .5
188 hue = .5 - (heat * .5)
189
190 return hue, saturation, luminosity
191
192
195
196
203