@@ -32,7 +32,29 @@ def create_dendrogram(
32
32
:param (ndarray) X: Matrix of observations as array of arrays
33
33
:param (str) orientation: 'top', 'right', 'bottom', or 'left'
34
34
:param (list) labels: List of axis category labels(observation labels)
35
- :param (list) colorscale: Optional colorscale for dendrogram tree
35
+ :param (list) colorscale: Optional colorscale for dendrogram tree. To
36
+ totally replace the default colorscale, a custom
37
+ colorscale must contain 8 colors, corresponding
38
+ to when the underlying
39
+ scipy.cluster.hierarchy.dendrogram specifies
40
+ 'b', 'c', 'g', 'k', 'm', 'r', 'w', 'y', in that
41
+ order. So if you want 'b', 'c', 'g', 'k', to map
42
+ to rgb(255,0,0) and 'm', 'r', 'w', 'y', to map
43
+ to rgb(0,255,0), the colorscale should be
44
+ ['rgb(255,0,0)','rgb(255,0,0)','rgb(255,0,0)',
45
+ 'rgb(255,0,0)','rgb(0,255,0)','rgb(0,255,0)',
46
+ 'rgb(0,255,0)','rgb(0,255,0)',] If using
47
+ scipy >= 1.5.1, instead of the letters above, the
48
+ colors are specfied as 'C0', 'C1', etc. and in
49
+ that case the list corresponds to the colors:
50
+ 'C0', 'C3' or 'C9', 'C1' or 'C7', 'C6', 'C2',
51
+ 'C4', 'C8',<ignored>, 'C5', 'C7', e.g., if
52
+ scipy.cluster.hierarchy.dendrogram uses the color
53
+ 'C3' or 'C9' this is mapped to the rgb value in
54
+ index 1, and there is not color that maps to index
55
+ 7, of the colorscale. If the colorscale has less
56
+ than 8 colors, the remaining colors remain the
57
+ default.
36
58
:param (function) distfun: Function to compute the pairwise distance from
37
59
the observations
38
60
:param (function) linkagefun: Function to compute the linkage matrix from
@@ -160,8 +182,8 @@ def __init__(
160
182
if len (self .zero_vals ) > len (yvals ) + 1 :
161
183
# If the length of zero_vals is larger than the length of yvals,
162
184
# it means that there are wrong vals because of the identicial samples.
163
- # Three and more identicial samples will make the yvals of spliting center into 0 and it will \
164
- # accidentally take it as leaves.
185
+ # Three and more identicial samples will make the yvals of spliting
186
+ # center into 0 and it will accidentally take it as leaves.
165
187
l_border = int (min (self .zero_vals ))
166
188
r_border = int (max (self .zero_vals ))
167
189
correct_leaves_pos = range (
@@ -185,6 +207,9 @@ def get_color_dict(self, colorscale):
185
207
186
208
# These are the color codes returned for dendrograms
187
209
# We're replacing them with nicer colors
210
+ # This list is the colors that can be used by dendrogram, which were
211
+ # determined as the combination of the default above_threshold_color and
212
+ # the default color palette (see scipy/cluster/hierarchy.py)
188
213
d = {
189
214
"r" : "red" ,
190
215
"g" : "green" ,
@@ -193,6 +218,8 @@ def get_color_dict(self, colorscale):
193
218
"m" : "magenta" ,
194
219
"y" : "yellow" ,
195
220
"k" : "black" ,
221
+ # TODO: 'w' doesn't seem to be in the default color
222
+ # palette in scipy/cluster/hierarchy.py
196
223
"w" : "white" ,
197
224
}
198
225
default_colors = OrderedDict (sorted (d .items (), key = lambda t : t [0 ]))
@@ -217,26 +244,32 @@ def get_color_dict(self, colorscale):
217
244
default_colors [k ] = rgb_colorscale [i ]
218
245
219
246
# add support for cyclic format colors as introduced in scipy===1.5.0
220
- # before this, color_list, from which the color_key is obtained was:
221
- # ['g', 'r', 'b', 'c', 'm', 'b', 'b', 'b', 'b'], now it is
222
- # ['C1', 'C2', 'C0', 'C3', 'C4', 'C0', 'C0', 'C0', 'C0'], so to keep the
223
- # colors consistent regardless of the version of scipy, 'C1' is mapped
224
- # to 'rgb(61,153,112)' (what 'g' was mapped to before), 'C2' is mapped
225
- # to 'rgb(255,65,54)', etc.
226
- cyclic_color_names = ["C%d" % (n ,) for n in range (5 )]
227
- if colorscale is None :
228
- cyclic_color_rgb = [
229
- "rgb(0,116,217)" ,
230
- "rgb(61,153,112)" ,
231
- "rgb(255,65,54)" ,
232
- "rgb(35,205,205)" ,
233
- "rgb(133,20,75)" ,
234
- ]
235
- else :
236
- cyclic_color_rgb = colorscale
237
-
238
- for k , c in zip (cyclic_color_names , cyclic_color_rgb ):
239
- default_colors [k ] = c
247
+ # before this, the colors were named 'r', 'b', 'y' etc., now they are
248
+ # named 'C0', 'C1', etc. To keep the colors consistent regardless of the
249
+ # scipy version, we try as much as possible to map the new colors to the
250
+ # old colors
251
+ # this mapping was found by inpecting scipy/cluster/hierarchy.py (see
252
+ # comment above).
253
+ new_old_color_map = [
254
+ ("C0" , "b" ),
255
+ ("C1" , "g" ),
256
+ ("C2" , "r" ),
257
+ ("C3" , "c" ),
258
+ ("C4" , "m" ),
259
+ ("C5" , "y" ),
260
+ ("C6" , "k" ),
261
+ ("C7" , "g" ),
262
+ ("C8" , "r" ),
263
+ ("C9" , "c" ),
264
+ ]
265
+ for nc , oc in new_old_color_map :
266
+ try :
267
+ default_colors [nc ] = default_colors [oc ]
268
+ except KeyError :
269
+ # it could happen that the old color isn't found (if a custom
270
+ # colorscale was specified), in this case we set it to an
271
+ # arbitrary default.
272
+ default_colors [n ] = "rgb(0,116,217)"
240
273
241
274
return default_colors
242
275
0 commit comments