Completed
Push — master ( f22d12...eec1c5 )
by Andrei
01:28
created

cluster_visualizer.__init__()   B

Complexity

Conditions 4

Size

Total Lines 50

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 50
rs 8.8571
1
"""!
2
3
@brief pyclustering module for cluster analysis.
4
5
@authors Andrei Novikov ([email protected])
6
@date 2014-2016
7
@copyright GNU Public License
8
9
@cond GNU_PUBLIC_LICENSE
10
    PyClustering is free software: you can redistribute it and/or modify
11
    it under the terms of the GNU General Public License as published by
12
    the Free Software Foundation, either version 3 of the License, or
13
    (at your option) any later version.
14
    
15
    PyClustering is distributed in the hope that it will be useful,
16
    but WITHOUT ANY WARRANTY; without even the implied warranty of
17
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
    GNU General Public License for more details.
19
    
20
    You should have received a copy of the GNU General Public License
21
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
@endcond
23
24
"""
25
26
import matplotlib.pyplot as plt;
27
import matplotlib.gridspec as gridspec;
28
29
import math;
30
31
32
class canvas_cluster_descr:
33
    """!
34
    @brief Description of cluster for representation on canvas.
35
    
36
    """
37
38
    def __init__(self, cluster, data, marker, markersize):
39
        """!
40
        @brief Constructor of cluster representation on the canvas.
41
        
42
        @param[in] cluster (list): Single cluster that consists of objects or indexes from data.
43
        @param[in] data (list): Objects that should be displayed, can be None if clusters consist of objects instead of indexes.
44
        @param[in] marker (string): Type of marker that is used for drawing objects.
45
        @param[in] markersize (uint): Size of marker that is used for drawing objects.
46
        
47
        """
48
        ## Cluster that may consist of objects or indexes of objects from data.
49
        self.cluster = cluster;
50
        
51
        ## Data where objects are stored. It can be None if clusters consist of objects instead of indexes.
52
        self.data = data;
53
        
54
        ## Marker that is used for drawing objects.
55
        self.marker = marker;
56
        
57
        ## Size of marker that is used for drawing objects.
58
        self.markersize = markersize;
59
    
60
61
class cluster_visualizer:
62
    """!
63
    @brief Common visualizer of clusters on 2D or 3D surface.
64
    
65
    """
66
    
67
    __colors = [ 'red', 'blue', 'darkgreen', 'brown', 'violet', 
68
                 'deepskyblue', 'darkgrey', 'lightsalmon', 'deeppink', 'yellow',
69
                 'black', 'mediumspringgreen', 'orange', 'darkviolet', 'darkblue',
70
                 'silver', 'lime', 'pink', 'gold', 'bisque' ];
71
    
72
73
    def __init__(self, number_canvases = 1, size_row = 1):
74
        """!
75
        @brief Constructor of cluster visualizer.
76
        
77
        @param[in] number_canvases (uint): Number of canvases that is used for visualization.
78
        @param[in] size_row (uint): Amount of canvases that can be placed in one row.
79
        
80
        Example:
81
        @code
82
            # load 2D data sample
83
            sample_2d = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1);
84
            
85
            # load 3D data sample
86
            sample_3d = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA);
87
            
88
            # extract clusters from the first sample using DBSCAN algorithm
89
            dbscan_instance = dbscan(sample_2d, 0.4, 2, False);
90
            dbscan_instance.process();
91
            clusters_sample_2d = dbscan_instance.get_clusters();
92
        
93
            # extract clusters from the second sample using DBSCAN algorithm
94
            dbscan_instance = dbscan(sample_3d, 1, 3, True);
95
            dbscan_instance.process();
96
            clusters_sample_3d = dbscan_instance.get_clusters();
97
            
98
            # create plot with two canvases where each row contains 2 canvases.
99
            size = 2;
100
            row_size = 2;
101
            visualizer = cluster_visualizer(size, row_size);
102
            
103
            # place clustering result of sample_2d to the first canvas
104
            visualizer.append_clusters(clusters_sample_2d, sample_2d, 0, markersize = 5);
105
            
106
            # place clustering result of sample_3d to the second canvas
107
            visualizer.append_clusters(clusters_sample_3d, sample_3d, 1, markersize = 30);
108
            
109
            # show plot
110
            visualizer.show();
111
        @endcode
112
        
113
        """
114
        
115
        self.__number_canvases = number_canvases;
116
        self.__size_row = size_row;
117
        self.__canvas_clusters = [ [] for i in range(number_canvases) ];
118
        self.__canvas_dimensions = [ None for i in range(number_canvases) ];
119
        self.__canvas_titles = [ None for i in range(number_canvases) ];
120
        
121
        self.__default_2d_marker_size = 5;
122
        self.__default_3d_marker_size = 30;
123
    
124
    
125
    def append_cluster(self, cluster, data = None, canvas = 0, marker = '.', markersize = None):
126
        """!
127
        @brief Appends cluster to canvas for drawing.
128
        
129
        @param[in] cluster (list): cluster that may consist of indexes of objects from the data or object itself.
130
        @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data.
131
        @param[in] canvas (uint): Number of canvas that should be used for displaying cluster.
132
        @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas.
133
        @param[in] markersize (uint): Size of marker.
134
        
135
        """
136
        
137
        if (len(cluster) == 0):
138
            return;
139
        
140
        if (canvas > self.__number_canvases):
141
            raise NameError('Canvas does ' + canvas + ' not exists.');
142
        
143
        added_canvas_descriptor = canvas_cluster_descr(cluster, data, marker, markersize);
144
        self.__canvas_clusters[canvas].append( added_canvas_descriptor );
145
        if (len(self.__canvas_clusters[canvas]) > len(self.__colors)):
146
            raise NameError('Not enough colors to display clusters.');
147
        
148
        dimension = 0;
149
        if (data is None):
150
            dimension = len(cluster[0]);
151
            if (self.__canvas_dimensions[canvas] is None):
152
                self.__canvas_dimensions[canvas] = dimension;
153
            elif (self.__canvas_dimensions[canvas] != dimension):
154
                raise NameError('Only clusters with the same dimension of objects can be displayed on canvas.');
155
                
156
        else:
157
            dimension = len(data[0]);
158
            if (self.__canvas_dimensions[canvas] is None):
159
                self.__canvas_dimensions[canvas] = dimension;
160
            elif (self.__canvas_dimensions[canvas] != dimension):
161
                raise NameError('Only clusters with the same dimension of objects can be displayed on canvas.');
162
163
        if ( (dimension < 1) and (dimension > 3) ):
164
            raise NameError('Only objects with size dimension 1 (1D plot), 2 (2D plot) or 3 (3D plot) can be displayed.');
165
        
166
        if (markersize is None):
167
            if (dimension == 2):
168
                added_canvas_descriptor.markersize = self.__default_2d_marker_size;
169
            elif (dimension == 3):
170
                added_canvas_descriptor.markersize = self.__default_3d_marker_size;
171
    
172
    
173
    def append_clusters(self, clusters, data = None, canvas = 0, marker = '.', markersize = None):
174
        """!
175
        @brief Appends list of cluster to canvas for drawing.
176
        
177
        @param[in] clusters (list): List of clusters where each cluster may consist of indexes of objects from the data or object itself.
178
        @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data.
179
        @param[in] canvas (uint): Number of canvas that should be used for displaying clusters.
180
        @param[in] marker (string): Marker that is used for displaying objects from clusters on the canvas.
181
        @param[in] markersize (uint): Size of marker.
182
        
183
        """
184
            
185
        for cluster in clusters:
186
            self.append_cluster(cluster, data, canvas, marker, markersize);
187
    
188
    
189
    def set_canvas_title(self, text, canvas):
190
        """!
191
        @brief Set title for specified canvas.
192
        
193
        @param[in] text (string): Title for canvas.
194
        @param[in] canvas (uint): Index of canvas where title should be displayed.
195
        
196
        """
197
        
198
        if (canvas > self.__number_canvases):
199
            raise NameError('Canvas does ' + canvas + ' not exists.');
200
        
201
        self.__canvas_titles[canvas] = text;
202
            
203
    
204
    
205
    def show(self, visible_axis = True, visible_grid = True):
206
        """!
207
        @brief Shows clusters (visualize).
208
        
209
        @param[in] visible_axis (bool): Defines visibility of axes on each canvas, if True - axes are invisible.
210
        @param[in] visible_grid (bool): Defines visibility of axes on each canvas, if True - grid is displayed.
211
        
212
        """
213
        
214
        maximum_cols = self.__size_row;
215
        maximum_rows = math.ceil(self.__number_canvases / maximum_cols);
216
        
217
        grid_spec = gridspec.GridSpec(maximum_rows, maximum_cols);
218
        
219
        for index_canvas in range(len(self.__canvas_clusters)):
220
            canvas = self.__canvas_clusters[index_canvas];
221
            dimension = self.__canvas_dimensions[index_canvas];
222
            
223
            #ax = axes[real_index];
224
            if (dimension == 2):
225
                ax = plt.subplot(grid_spec[index_canvas]);
226
            else:
227
                ax = plt.subplot(grid_spec[index_canvas], projection='3d');
228
            
229
            if (len(canvas) == 0):
230
                plt.setp(ax, visible = False);
231
            
232
            for index_cluster in range(len(canvas)):
233
                cluster = canvas[index_cluster].cluster;
234
                data = canvas[index_cluster].data;
235
                marker = canvas[index_cluster].marker;
236
                markersize = canvas[index_cluster].markersize;
237
                color = self.__colors[index_cluster];
238
                
239
                for item in cluster:
240
                    if (dimension == 1):
241
                        if (data is None):
242
                            ax.plot(item[0], 0.0, color = color, marker = marker, markersize = markersize);
243
                        else:
244
                            ax.plot(data[item][0], 0.0, color = color, marker = marker, markersize = markersize);
245
246
                    if (dimension == 2):
247
                        if (data is None):
248
                            ax.plot(item[0], item[1], color = color, marker = marker, markersize = markersize);
249
                        else:
250
                            ax.plot(data[item][0], data[item][1], color = color, marker = marker, markersize = markersize);
251
                
252 View Code Duplication
                    elif (dimension == 3):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
253
                        if (data is None):
254
                            ax.scatter(item[0], item[1], item[2], c = color, marker = marker, s = markersize);
255
                        else:
256
                            ax.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker, s = markersize);
257
                            
258
            if (visible_axis is True):
259
                ax.xaxis.set_ticklabels([]);
260
                ax.yaxis.set_ticklabels([]);
261
                
262
                if (dimension == 3):
263
                    ax.zaxis.set_ticklabels([]);
264
            
265
            if (self.__canvas_titles[index_canvas] is not None):
266
                ax.set_title(self.__canvas_titles[index_canvas]);
267
            
268
            ax.grid(visible_grid);
269
        
270
        plt.show();
271
272