15
15
import six
16
16
17
17
import math
18
+ import scipy
18
19
20
+ import scipy .cluster .hierarchy as sch
19
21
20
22
from plotly import utils
21
23
from plotly import exceptions
22
24
from plotly import session
23
25
24
26
from plotly .graph_objs import graph_objs
25
- from plotly .graph_objs import Scatter , Marker
27
+ from plotly .graph_objs import Scatter , Marker , Line , Data
26
28
27
29
28
30
# Warning format
@@ -1760,6 +1762,7 @@ def create_streamline(x, y, u, v,
1760
1762
y = streamline_y + arrow_y ,
1761
1763
mode = 'lines' , ** kwargs )
1762
1764
1765
+ < << << << HEAD
1763
1766
data = [streamline ]
1764
1767
layout = graph_objs .Layout (hovermode = 'closest' )
1765
1768
@@ -2275,6 +2278,23 @@ def create_candlestick(open, high, low, close,
2275
2278
return dict (data = data , layout = layout )
2276
2279
2277
2280
2281
+ @staticmethod
2282
+ def create_dendrogram (X , orientation = "bottom" , labels = None ,
2283
+ colorscale = None , ** kwargs ):
2284
+ """
2285
+ Returns a dendrogram Plotly figure object.
2286
+
2287
+ X: Heatmap matrix as array of arrays
2288
+ orientation: 'top', 'right', 'bottom', or 'left'
2289
+ labels: List of axis category labels
2290
+ colorscale: Optional colorscale for dendgrogram tree clusters
2291
+ """
2292
+
2293
+ #TODO: add validations of input
2294
+
2295
+ dendrogram = _Dendrogram (X , orientation , labels , colorscale )
2296
+ return dendrogram
2297
+
2278
2298
class _Quiver (FigureFactory ):
2279
2299
"""
2280
2300
Refer to FigureFactory.create_quiver() for docstring
@@ -2690,6 +2710,7 @@ def sum_streamlines(self):
2690
2710
streamline_y = sum (self .st_y , [])
2691
2711
return streamline_x , streamline_y
2692
2712
2713
+ < << << << HEAD
2693
2714
2694
2715
class _OHLC (FigureFactory ):
2695
2716
"""
@@ -2871,3 +2892,149 @@ def get_candle_decrease(self):
2871
2892
return (decrease_x , decrease_close , decrease_dif ,
2872
2893
stick_decrease_y , stick_decrease_x )
2873
2894
2895
+ class _Dendrogram (TraceFactory ):
2896
+ ''' Returns a Dendrogram figure object
2897
+ Example usage:
2898
+ D = Dendrogram( Z )
2899
+ fig = { 'data':D.data, 'layout':D.layout }
2900
+ py.iplot( fig, filename='Dendro', validate=False )'''
2901
+
2902
+ def __init__ (self , X , orientation = 'bottom' , labels = None , colorscale = None , \
2903
+ width = 700 , height = 700 , xaxis = 'xaxis' , yaxis = 'yaxis' ):
2904
+ ''' Draw a 2d dendrogram tree
2905
+ X: Heatmap matrix as array of arrays
2906
+ orientation: 'top', 'right', 'bottom', or 'left'
2907
+ labels: List of axis category labels
2908
+ colorscale: Optional colorscale for dendgrogram tree clusters
2909
+ Returns a dendrogram Plotly figure object '''
2910
+
2911
+ self .orientation = orientation
2912
+ self .labels = labels
2913
+ self .xaxis = xaxis
2914
+ self .yaxis = yaxis
2915
+ self .data = []
2916
+ self .leaves = []
2917
+ self .sign = { self .xaxis :1 , self .yaxis :1 }
2918
+ self .layout = { self .xaxis :{}, self .yaxis :{} }
2919
+
2920
+ self .sign [self .xaxis ] = 1 if self .orientation in ['left' ,'bottom' ] else - 1
2921
+ self .sign [self .yaxis ] = 1 if self .orientation in ['right' ,'bottom' ] else - 1
2922
+
2923
+ dd_traces , xvals , yvals , ordered_labels , leaves = self .get_dendrogram_traces ( X , colorscale )
2924
+
2925
+ self .labels = ordered_labels
2926
+ self .leaves = leaves
2927
+ yvals_flat = yvals .flatten ()
2928
+ xvals_flat = xvals .flatten ()
2929
+
2930
+ self .zero_vals = []
2931
+
2932
+ for i in range (len (yvals_flat )):
2933
+ if yvals_flat [i ] == 0.0 and xvals_flat [i ] not in self .zero_vals :
2934
+ self .zero_vals .append ( xvals_flat [i ] )
2935
+
2936
+ self .zero_vals .sort ()
2937
+
2938
+ self .layout = self .set_figure_layout ( width , height )
2939
+ self .data = Data ( dd_traces )
2940
+
2941
+ def get_color_dict ( self , colorscale ):
2942
+ ''' Return colorscale used for dendrogram tree clusters '''
2943
+
2944
+ # These are the color codes returned for dendrograms
2945
+ # We're replacing them with nicer colors
2946
+ default_colors = {'r' :'red' ,'g' :'green' ,'b' :'blue' ,'c' :'cyan' ,\
2947
+ 'm' :'magenta' ,'y' :'yellow' ,'k' :'black' ,'w' :'white' }
2948
+
2949
+ if colorscale is None :
2950
+ colorscale = [
2951
+ "rgb(0,116,217)" ,
2952
+ "rgb(255,65,54)" ,
2953
+ "rgb(133,20,75)" ,
2954
+ "rgb(255,133,27)" ,
2955
+ "rgb(255,220,0)" ,
2956
+ "rgb(61,153,112)" ]
2957
+ for i in range (len (default_colors .keys ())):
2958
+ k = default_colors .keys ()[i ]
2959
+ if i < len ( colorscale ):
2960
+ default_colors [k ] = colorscale [i ]
2961
+
2962
+ return default_colors
2963
+
2964
+ def set_axis_layout ( self , axis_key ):
2965
+ ''' Sets and returns default axis object for dendrogram figure
2966
+ axis_key: "xaxis", "xaxis1", "yaxis", yaxis1", etc '''
2967
+
2968
+ axis_defaults = {
2969
+ 'type' : 'linear' ,
2970
+ 'ticks' : 'inside' ,
2971
+ 'mirror' : 'allticks' ,
2972
+ 'rangemode' : 'tozero' ,
2973
+ 'showticklabels' : True ,
2974
+ 'zeroline' : False ,
2975
+ 'showgrid' : False ,
2976
+ 'showline' : True ,
2977
+ }
2978
+
2979
+ if self .labels != None :
2980
+ axis_key_labels = self .xaxis
2981
+ if self .orientation in ['left' ,'right' ]:
2982
+ axis_key_labels = self .yaxis
2983
+ if axis_key_labels not in self .layout :
2984
+ self .layout [axis_key_labels ] = {}
2985
+ self .layout [axis_key_labels ]['tickvals' ] = [ea * self .sign [axis_key ] for ea in self .zero_vals ]
2986
+ self .layout [axis_key_labels ]['ticktext' ] = self .labels
2987
+ self .layout [axis_key_labels ]['tickmode' ] = 'array'
2988
+
2989
+ self .layout [axis_key ].update ( axis_defaults )
2990
+
2991
+ return self .layout [axis_key ]
2992
+
2993
+ def set_figure_layout ( self , width , height ):
2994
+ ''' Sets and returns default layout object for dendrogram figure '''
2995
+
2996
+ self .layout .update ({
2997
+ 'showlegend' :False ,
2998
+ 'autoscale' :False ,
2999
+ 'hovermode' :'closest' ,
3000
+ 'width' :width ,
3001
+ 'width' :height
3002
+ })
3003
+
3004
+ self .set_axis_layout (self .xaxis )
3005
+ self .set_axis_layout (self .yaxis )
3006
+
3007
+ return self .layout
3008
+
3009
+ def get_dendrogram_traces ( self , X , colorscale ):
3010
+ ''' Returns a tuple with:
3011
+ (a) List of Plotly trace objects for the dendrogram tree
3012
+ (b) icoord: All X points of the dendogram tree as array of arrays with lenght 4
3013
+ (c) dcoord: All Y points of the dendogram tree as array of arrays with lenght 4 '''
3014
+
3015
+ d = sch .distance .pdist (X )
3016
+ Z = sch .linkage (d , method = 'complete' )
3017
+ P = sch .dendrogram (Z ,orientation = self .orientation ,labels = self .labels , no_plot = True )
3018
+
3019
+ icoord = scipy .array ( P ['icoord' ] )
3020
+ dcoord = scipy .array ( P ['dcoord' ] )
3021
+ ordered_labels = scipy .array ( P ['ivl' ] )
3022
+ color_list = scipy .array ( P ['color_list' ] )
3023
+ colors = self .get_color_dict ( colorscale )
3024
+
3025
+ trace_list = []
3026
+
3027
+ for i in range (len (icoord )):
3028
+ # xs and ys are arrays of 4 points that make up the '∩' shapes of the dendrogram tree
3029
+ xs = icoord [i ] if self .orientation in ['top' ,'bottom' ] else dcoord [i ]
3030
+ ys = dcoord [i ] if self .orientation in ['top' ,'bottom' ] else icoord [i ]
3031
+ color_key = color_list [i ]
3032
+ trace = Scatter (x = np .multiply (self .sign [self .xaxis ],xs ), \
3033
+ y = np .multiply (self .sign [self .yaxis ],ys ), \
3034
+ mode = 'lines' , marker = Marker (color = colors [color_key ]) )
3035
+ trace ['xaxis' ] = 'x' + self .xaxis [- 1 ]
3036
+ trace ['yaxis' ] = 'y' + self .yaxis [- 1 ]
3037
+ trace_list .append ( trace )
3038
+
3039
+ return trace_list , icoord , dcoord , ordered_labels , P ['leaves' ]
3040
+
0 commit comments