3
3
from collections import OrderedDict
4
4
import plotly .graph_objs as go
5
5
6
- def plot_dendrogram (Z_dendrogram , cutoff_line = True , value = 15 , orientation = 'bottom' , hang = 30 , hide_labels = False , labels = None ,
7
- colorscale = None , hovertext = None , color_threshold = None ):
6
+
7
+ def plot_dendrogram (
8
+ Z_dendrogram ,
9
+ cutoff_line = True ,
10
+ value = 15 ,
11
+ orientation = "bottom" ,
12
+ hang = 30 ,
13
+ hide_labels = False ,
14
+ labels = None ,
15
+ colorscale = None ,
16
+ hovertext = None ,
17
+ color_threshold = None ,
18
+ ):
8
19
"""
9
20
Modified version of Plotly _dendrogram.py that returns a dendrogram Plotly figure object with cutoff line.
10
21
@@ -36,25 +47,59 @@ def plot_dendrogram(Z_dendrogram, cutoff_line=True, value=15, orientation='botto
36
47
figure = plot_dendrogram(dendro_tree, hang=0.9, cutoff_line=False)
37
48
"""
38
49
39
- dendrogram = Dendrogram (Z_dendrogram , orientation , hang , hide_labels , labels , colorscale , hovertext = hovertext , color_threshold = color_threshold )
50
+ dendrogram = Dendrogram (
51
+ Z_dendrogram ,
52
+ orientation ,
53
+ hang ,
54
+ hide_labels ,
55
+ labels ,
56
+ colorscale ,
57
+ hovertext = hovertext ,
58
+ color_threshold = color_threshold ,
59
+ )
40
60
41
61
if cutoff_line == True :
42
- dendrogram .layout .update ({'shapes' :[{'type' :'line' ,
43
- 'xref' :'paper' ,
44
- 'yref' :'y' ,
45
- 'x0' :0 , 'y0' :value ,
46
- 'x1' :1 , 'y1' :value ,
47
- 'line' :{'color' :'red' }}]})
62
+ dendrogram .layout .update (
63
+ {
64
+ "shapes" : [
65
+ {
66
+ "type" : "line" ,
67
+ "xref" : "paper" ,
68
+ "yref" : "y" ,
69
+ "x0" : 0 ,
70
+ "y0" : value ,
71
+ "x1" : 1 ,
72
+ "y1" : value ,
73
+ "line" : {"color" : "red" },
74
+ }
75
+ ]
76
+ }
77
+ )
48
78
49
79
figure = dict (data = dendrogram .data , layout = dendrogram .layout )
50
- figure [' layout' ][ ' template' ] = ' plotly_white'
80
+ figure [" layout" ][ " template" ] = " plotly_white"
51
81
52
82
return figure
53
83
84
+
54
85
class Dendrogram (object ):
55
86
"""Refer to plot_dendrogram() for docstring."""
56
- def __init__ (self , Z_dendrogram , orientation = 'bottom' , hang = 1 , hide_labels = False , labels = None , colorscale = None , hovertext = None ,
57
- color_threshold = None , width = np .inf , height = np .inf , xaxis = 'xaxis' , yaxis = 'yaxis' ):
87
+
88
+ def __init__ (
89
+ self ,
90
+ Z_dendrogram ,
91
+ orientation = "bottom" ,
92
+ hang = 1 ,
93
+ hide_labels = False ,
94
+ labels = None ,
95
+ colorscale = None ,
96
+ hovertext = None ,
97
+ color_threshold = None ,
98
+ width = np .inf ,
99
+ height = np .inf ,
100
+ xaxis = "xaxis" ,
101
+ yaxis = "yaxis" ,
102
+ ):
58
103
self .orientation = orientation
59
104
self .labels = labels
60
105
self .xaxis = xaxis
@@ -64,20 +109,19 @@ def __init__(self, Z_dendrogram, orientation='bottom', hang=1, hide_labels=False
64
109
self .sign = {self .xaxis : 1 , self .yaxis : 1 }
65
110
self .layout = {self .xaxis : {}, self .yaxis : {}}
66
111
67
- if self .orientation in [' left' , ' bottom' ]:
112
+ if self .orientation in [" left" , " bottom" ]:
68
113
self .sign [self .xaxis ] = 1
69
114
else :
70
115
self .sign [self .xaxis ] = - 1
71
116
72
- if self .orientation in [' right' , ' bottom' ]:
117
+ if self .orientation in [" right" , " bottom" ]:
73
118
self .sign [self .yaxis ] = 1
74
119
else :
75
120
self .sign [self .yaxis ] = - 1
76
121
77
- (dd_traces , xvals , yvals ,
78
- ordered_labels , leaves ) = self .get_dendrogram_traces (Z_dendrogram , hang , colorscale ,
79
- hovertext ,
80
- color_threshold )
122
+ (dd_traces , xvals , yvals , ordered_labels , leaves ) = self .get_dendrogram_traces (
123
+ Z_dendrogram , hang , colorscale , hovertext , color_threshold
124
+ )
81
125
82
126
self .labels = ordered_labels
83
127
self .leaves = leaves
@@ -93,9 +137,9 @@ def __init__(self, Z_dendrogram, orientation='bottom', hang=1, hide_labels=False
93
137
if len (self .zero_vals ) > len (yvals ) + 1 :
94
138
l_border = int (min (self .zero_vals ))
95
139
r_border = int (max (self .zero_vals ))
96
- correct_leaves_pos = range (l_border ,
97
- r_border + 1 ,
98
- int (( r_border - l_border ) / len ( yvals )) )
140
+ correct_leaves_pos = range (
141
+ l_border , r_border + 1 , int (( r_border - l_border ) / len ( yvals ))
142
+ )
99
143
self .zero_vals = [v for v in correct_leaves_pos ]
100
144
101
145
self .zero_vals .sort ()
@@ -113,26 +157,29 @@ def get_color_dict(self, colorscale):
113
157
114
158
# These are the color codes returned for dendrograms
115
159
# We're replacing them with nicer colors
116
- d = {'r' : 'red' ,
117
- 'g' : 'green' ,
118
- 'b' : 'blue' ,
119
- 'c' : 'cyan' ,
120
- 'm' : 'magenta' ,
121
- 'y' : 'yellow' ,
122
- 'k' : 'black' ,
123
- 'w' : 'white' }
160
+ d = {
161
+ "r" : "red" ,
162
+ "g" : "green" ,
163
+ "b" : "blue" ,
164
+ "c" : "cyan" ,
165
+ "m" : "magenta" ,
166
+ "y" : "yellow" ,
167
+ "k" : "black" ,
168
+ "w" : "white" ,
169
+ }
124
170
default_colors = OrderedDict (sorted (d .items (), key = lambda t : t [0 ]))
125
171
126
172
if colorscale is None :
127
173
colorscale = [
128
- 'rgb(0,116,217)' , # blue
129
- 'rgb(35,205,205)' , # cyan
130
- 'rgb(61,153,112)' , # green
131
- 'rgb(40,35,35)' , # black
132
- 'rgb(133,20,75)' , # magenta
133
- 'rgb(255,65,54)' , # red
134
- 'rgb(255,255,255)' , # white
135
- 'rgb(255,220,0)' ] # yellow
174
+ "rgb(0,116,217)" , # blue
175
+ "rgb(35,205,205)" , # cyan
176
+ "rgb(61,153,112)" , # green
177
+ "rgb(40,35,35)" , # black
178
+ "rgb(133,20,75)" , # magenta
179
+ "rgb(255,65,54)" , # red
180
+ "rgb(255,255,255)" , # white
181
+ "rgb(255,220,0)" ,
182
+ ] # yellow
136
183
137
184
for i in range (len (default_colors .keys ())):
138
185
k = list (default_colors .keys ())[i ] # PY3 won't index keys
@@ -150,32 +197,34 @@ def set_axis_layout(self, axis_key, hide_labels):
150
197
:return (dict): An axis_key dictionary with set parameters.
151
198
"""
152
199
axis_defaults = {
153
- ' type' : ' linear' ,
154
- ' ticks' : ' outside' ,
155
- ' mirror' : ' allticks' ,
156
- ' rangemode' : ' tozero' ,
157
- ' showticklabels' : True ,
158
- ' zeroline' : False ,
159
- ' showgrid' : False ,
160
- ' showline' : True ,
161
- }
200
+ " type" : " linear" ,
201
+ " ticks" : " outside" ,
202
+ " mirror" : " allticks" ,
203
+ " rangemode" : " tozero" ,
204
+ " showticklabels" : True ,
205
+ " zeroline" : False ,
206
+ " showgrid" : False ,
207
+ " showline" : True ,
208
+ }
162
209
163
210
if len (self .labels ) != 0 :
164
211
axis_key_labels = self .xaxis
165
- if self .orientation in [' left' , ' right' ]:
212
+ if self .orientation in [" left" , " right" ]:
166
213
axis_key_labels = self .yaxis
167
214
if axis_key_labels not in self .layout :
168
215
self .layout [axis_key_labels ] = {}
169
- self .layout [axis_key_labels ]['tickvals' ] = \
170
- [zv * self .sign [axis_key ] for zv in self .zero_vals ]
171
- self .layout [axis_key_labels ]['ticktext' ] = self .labels
172
- self .layout [axis_key_labels ]['tickmode' ] = 'array'
216
+ self .layout [axis_key_labels ]["tickvals" ] = [
217
+ zv * self .sign [axis_key ] for zv in self .zero_vals
218
+ ]
219
+ self .layout [axis_key_labels ]["ticktext" ] = self .labels
220
+ self .layout [axis_key_labels ]["tickmode" ] = "array"
173
221
174
222
self .layout [axis_key ].update (axis_defaults )
175
223
176
224
if hide_labels == True :
177
- self .layout [axis_key ].update ({'showticklabels' : False })
178
- else : pass
225
+ self .layout [axis_key ].update ({"showticklabels" : False })
226
+ else :
227
+ pass
179
228
180
229
return self .layout [axis_key ]
181
230
@@ -191,24 +240,27 @@ def set_figure_layout(self, width, height, hide_labels):
191
240
:type hide_labels: boolean
192
241
:return: Plotly layout
193
242
"""
194
- self .layout .update ({
195
- 'showlegend' : False ,
196
- 'autosize' : False ,
197
- 'hovermode' : 'closest' ,
198
- 'width' : width ,
199
- 'height' : height
200
- })
243
+ self .layout .update (
244
+ {
245
+ "showlegend" : False ,
246
+ "autosize" : False ,
247
+ "hovermode" : "closest" ,
248
+ "width" : width ,
249
+ "height" : height ,
250
+ }
251
+ )
201
252
202
253
self .set_axis_layout (self .xaxis , hide_labels = hide_labels )
203
254
self .set_axis_layout (self .yaxis , hide_labels = False )
204
255
205
256
return self .layout
206
257
207
-
208
- def get_dendrogram_traces (self , Z_dendrogram , hang , colorscale , hovertext , color_threshold ):
258
+ def get_dendrogram_traces (
259
+ self , Z_dendrogram , hang , colorscale , hovertext , color_threshold
260
+ ):
209
261
"""
210
262
Calculates all the elements needed for plotting a dendrogram.
211
-
263
+
212
264
:param Z_dendrogram: Matrix of observations as array of arrays
213
265
:type Z_dendrogram: ndarray
214
266
:param hang: dendrogram distance of leaf lines
@@ -218,28 +270,28 @@ def get_dendrogram_traces(self, Z_dendrogram, hang, colorscale, hovertext, color
218
270
:param hovertext: List of hovertext for constituent traces of dendrogram
219
271
:type hovertext: list
220
272
:return (tuple): Contains all the traces in the following order:
221
-
273
+
222
274
a. trace_list: List of Plotly trace objects for dendrogram tree
223
275
b. icoord: All X points of the dendrogram tree as array of arrays with length 4
224
276
c. dcoord: All Y points of the dendrogram tree as array of arrays with length 4
225
277
d. ordered_labels: leaf labels in the order they are going to appear on the plot
226
278
e. Z_dendrogram['leaves']: left-to-right traversal of the leaves
227
279
"""
228
- icoord = scp .array (Z_dendrogram [' icoord' ])
229
- dcoord = scp .array (Z_dendrogram [' dcoord' ])
230
- ordered_labels = scp .array (Z_dendrogram [' ivl' ])
231
- color_list = scp .array (Z_dendrogram [' color_list' ])
280
+ icoord = scp .array (Z_dendrogram [" icoord" ])
281
+ dcoord = scp .array (Z_dendrogram [" dcoord" ])
282
+ ordered_labels = scp .array (Z_dendrogram [" ivl" ])
283
+ color_list = scp .array (Z_dendrogram [" color_list" ])
232
284
colors = self .get_color_dict (colorscale )
233
285
234
286
trace_list = []
235
287
236
288
for i in range (len (icoord )):
237
- if self .orientation in [' top' , ' bottom' ]:
289
+ if self .orientation in [" top" , " bottom" ]:
238
290
xs = icoord [i ]
239
291
else :
240
292
xs = dcoord [i ]
241
293
242
- if self .orientation in [' top' , ' bottom' ]:
294
+ if self .orientation in [" top" , " bottom" ]:
243
295
ys = dcoord [i ]
244
296
else :
245
297
ys = icoord [i ]
@@ -264,28 +316,31 @@ def get_dendrogram_traces(self, Z_dendrogram, hang, colorscale, hovertext, color
264
316
y_coord .append (y )
265
317
266
318
trace = dict (
267
- type = ' scattergl' ,
319
+ type = " scattergl" ,
268
320
x = np .multiply (self .sign [self .xaxis ], x_coord ),
269
321
y = np .multiply (self .sign [self .yaxis ], y_coord ),
270
- mode = 'lines' ,
271
- marker = dict (color = 'rgb(40,35,35)' ),
272
- line = dict (color = 'rgb(40,35,35)' , width = 1 ), #dict(color=colors[color_key]),
322
+ mode = "lines" ,
323
+ marker = dict (color = "rgb(40,35,35)" ),
324
+ line = dict (
325
+ color = "rgb(40,35,35)" , width = 1
326
+ ), # dict(color=colors[color_key]),
273
327
text = hovertext_label ,
274
- hoverinfo = 'text' )
328
+ hoverinfo = "text" ,
329
+ )
275
330
276
331
try :
277
332
x_index = int (self .xaxis [- 1 ])
278
333
except ValueError :
279
- x_index = ''
334
+ x_index = ""
280
335
281
336
try :
282
337
y_index = int (self .yaxis [- 1 ])
283
338
except ValueError :
284
- y_index = ''
339
+ y_index = ""
285
340
286
- trace [' xaxis' ] = 'x' + x_index
287
- trace [' yaxis' ] = 'y' + y_index
341
+ trace [" xaxis" ] = "x" + x_index
342
+ trace [" yaxis" ] = "y" + y_index
288
343
289
344
trace_list .append (trace )
290
345
291
- return trace_list , icoord , dcoord , ordered_labels , Z_dendrogram [' leaves' ]
346
+ return trace_list , icoord , dcoord , ordered_labels , Z_dendrogram [" leaves" ]
0 commit comments