Total Complexity | 46 |
Total Lines | 270 |
Duplicated Lines | 3.33 % |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like cluster_visualizer often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | """! |
||
70 | class cluster_visualizer: |
||
71 | """! |
||
72 | @brief Common visualizer of clusters on 2D or 3D surface. |
||
73 | |||
74 | """ |
||
75 | |||
76 | def __init__(self, number_canvases = 1, size_row = 1): |
||
77 | """! |
||
78 | @brief Constructor of cluster visualizer. |
||
79 | |||
80 | @param[in] number_canvases (uint): Number of canvases that is used for visualization. |
||
81 | @param[in] size_row (uint): Amount of canvases that can be placed in one row. |
||
82 | |||
83 | Example: |
||
84 | @code |
||
85 | # load 2D data sample |
||
86 | sample_2d = read_sample(SIMPLE_SAMPLES.SAMPLE_SIMPLE1); |
||
87 | |||
88 | # load 3D data sample |
||
89 | sample_3d = read_sample(FCPS_SAMPLES.SAMPLE_HEPTA); |
||
90 | |||
91 | # extract clusters from the first sample using DBSCAN algorithm |
||
92 | dbscan_instance = dbscan(sample_2d, 0.4, 2, False); |
||
93 | dbscan_instance.process(); |
||
94 | clusters_sample_2d = dbscan_instance.get_clusters(); |
||
95 | |||
96 | # extract clusters from the second sample using DBSCAN algorithm |
||
97 | dbscan_instance = dbscan(sample_3d, 1, 3, True); |
||
98 | dbscan_instance.process(); |
||
99 | clusters_sample_3d = dbscan_instance.get_clusters(); |
||
100 | |||
101 | # create plot with two canvases where each row contains 2 canvases. |
||
102 | size = 2; |
||
103 | row_size = 2; |
||
104 | visualizer = cluster_visualizer(size, row_size); |
||
105 | |||
106 | # place clustering result of sample_2d to the first canvas |
||
107 | visualizer.append_clusters(clusters_sample_2d, sample_2d, 0, markersize = 5); |
||
108 | |||
109 | # place clustering result of sample_3d to the second canvas |
||
110 | visualizer.append_clusters(clusters_sample_3d, sample_3d, 1, markersize = 30); |
||
111 | |||
112 | # show plot |
||
113 | visualizer.show(); |
||
114 | @endcode |
||
115 | |||
116 | """ |
||
117 | |||
118 | self.__number_canvases = number_canvases; |
||
119 | self.__size_row = size_row; |
||
120 | self.__canvas_clusters = [ [] for _ in range(number_canvases) ]; |
||
121 | self.__canvas_dimensions = [ None for _ in range(number_canvases) ]; |
||
122 | self.__canvas_titles = [ None for _ in range(number_canvases) ]; |
||
123 | |||
124 | self.__default_2d_marker_size = 5; |
||
125 | self.__default_3d_marker_size = 30; |
||
126 | |||
127 | |||
128 | def append_cluster(self, cluster, data = None, canvas = 0, marker = '.', markersize = None, color = None): |
||
129 | """! |
||
130 | @brief Appends cluster to canvas for drawing. |
||
131 | |||
132 | @param[in] cluster (list): cluster that may consist of indexes of objects from the data or object itself. |
||
133 | @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. |
||
134 | @param[in] canvas (uint): Number of canvas that should be used for displaying cluster. |
||
135 | @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas. |
||
136 | @param[in] markersize (uint): Size of marker. |
||
137 | @param[in] color (string): Color of marker. |
||
138 | |||
139 | @return Returns index of cluster descriptor on the canvas. |
||
140 | |||
141 | """ |
||
142 | |||
143 | if (len(cluster) == 0): |
||
144 | return; |
||
145 | |||
146 | if (canvas > self.__number_canvases): |
||
147 | raise NameError('Canvas does ' + canvas + ' not exists.'); |
||
148 | |||
149 | if (color is None): |
||
150 | index_color = len(self.__canvas_clusters[canvas]) % len(color_list.TITLES); |
||
151 | color = color_list.TITLES[index_color]; |
||
152 | |||
153 | added_canvas_descriptor = canvas_cluster_descr(cluster, data, marker, markersize, color); |
||
154 | self.__canvas_clusters[canvas].append( added_canvas_descriptor ); |
||
155 | |||
156 | dimension = 0; |
||
157 | if (data is None): |
||
158 | dimension = len(cluster[0]); |
||
159 | if (self.__canvas_dimensions[canvas] is None): |
||
160 | self.__canvas_dimensions[canvas] = dimension; |
||
161 | elif (self.__canvas_dimensions[canvas] != dimension): |
||
162 | raise NameError('Only clusters with the same dimension of objects can be displayed on canvas.'); |
||
163 | |||
164 | else: |
||
165 | dimension = len(data[0]); |
||
166 | if (self.__canvas_dimensions[canvas] is None): |
||
167 | self.__canvas_dimensions[canvas] = dimension; |
||
168 | elif (self.__canvas_dimensions[canvas] != dimension): |
||
169 | raise NameError('Only clusters with the same dimension of objects can be displayed on canvas.'); |
||
170 | |||
171 | if ( (dimension < 1) and (dimension > 3) ): |
||
172 | raise NameError('Only objects with size dimension 1 (1D plot), 2 (2D plot) or 3 (3D plot) can be displayed.'); |
||
173 | |||
174 | if (markersize is None): |
||
175 | if ( (dimension == 1) or (dimension == 2) ): |
||
176 | added_canvas_descriptor.markersize = self.__default_2d_marker_size; |
||
177 | elif (dimension == 3): |
||
178 | added_canvas_descriptor.markersize = self.__default_3d_marker_size; |
||
179 | |||
180 | return len(self.__canvas_clusters[canvas]) - 1; |
||
181 | |||
182 | |||
183 | def append_cluster_attribute(self, index_canvas, index_cluster, data, marker = None, markersize = None): |
||
184 | """! |
||
185 | @brief Append cluster attribure for cluster on specific canvas. |
||
186 | @details Attribute it is data that is visualized for specific cluster using its color, marker and markersize if last two is not specified. |
||
187 | |||
188 | @param[in] index_canvas (uint): Index canvas where cluster is located. |
||
189 | @param[in] index_cluster (uint): Index cluster whose attribute should be added. |
||
190 | @param[in] data (list): List of points (data) that represents attribute. |
||
191 | @param[in] marker (string): Marker that is used for displaying objects from cluster on the canvas. |
||
192 | @param[in] markersize (uint): Size of marker. |
||
193 | |||
194 | """ |
||
195 | |||
196 | cluster_descr = self.__canvas_clusters[index_canvas][index_cluster]; |
||
197 | attribute_marker = marker; |
||
198 | if (attribute_marker is None): |
||
199 | attribute_marker = cluster_descr.marker; |
||
200 | |||
201 | attribure_markersize = markersize; |
||
202 | if (attribure_markersize is None): |
||
203 | attribure_markersize = cluster_descr.markersize; |
||
204 | |||
205 | attribute_color = cluster_descr.color; |
||
206 | |||
207 | added_attribute_cluster_descriptor = canvas_cluster_descr(data, None, attribute_marker, attribure_markersize, attribute_color); |
||
208 | self.__canvas_clusters[index_canvas][index_cluster].attributes.append(added_attribute_cluster_descriptor); |
||
209 | |||
210 | |||
211 | def append_clusters(self, clusters, data = None, canvas = 0, marker = '.', markersize = None): |
||
212 | """! |
||
213 | @brief Appends list of cluster to canvas for drawing. |
||
214 | |||
215 | @param[in] clusters (list): List of clusters where each cluster may consist of indexes of objects from the data or object itself. |
||
216 | @param[in] data (list): If defines that each element of cluster is considered as a index of object from the data. |
||
217 | @param[in] canvas (uint): Number of canvas that should be used for displaying clusters. |
||
218 | @param[in] marker (string): Marker that is used for displaying objects from clusters on the canvas. |
||
219 | @param[in] markersize (uint): Size of marker. |
||
220 | |||
221 | """ |
||
222 | |||
223 | for cluster in clusters: |
||
224 | self.append_cluster(cluster, data, canvas, marker, markersize); |
||
225 | |||
226 | |||
227 | def set_canvas_title(self, text, canvas = 0): |
||
228 | """! |
||
229 | @brief Set title for specified canvas. |
||
230 | |||
231 | @param[in] text (string): Title for canvas. |
||
232 | @param[in] canvas (uint): Index of canvas where title should be displayed. |
||
233 | |||
234 | """ |
||
235 | |||
236 | if (canvas > self.__number_canvases): |
||
237 | raise NameError('Canvas does ' + canvas + ' not exists.'); |
||
238 | |||
239 | self.__canvas_titles[canvas] = text; |
||
240 | |||
241 | |||
242 | def show(self, figure = None, visible_axis = True, visible_grid = True, display = True): |
||
243 | """! |
||
244 | @brief Shows clusters (visualize). |
||
245 | |||
246 | @param[in] figure (fig): Defines requirement to use specified figure, if None - new figure is created for drawing clusters. |
||
247 | @param[in] visible_axis (bool): Defines visibility of axes on each canvas, if True - axes are invisible. |
||
248 | @param[in] visible_grid (bool): Defines visibility of axes on each canvas, if True - grid is displayed. |
||
249 | @param[in] display (bool): Defines requirement to display clusters on a stage, if True - clusters are displayed, if False - plt.show() should be called by user." |
||
250 | |||
251 | @return (fig) Figure where clusters are shown. |
||
252 | |||
253 | """ |
||
254 | |||
255 | canvas_shift = 0; |
||
256 | cluster_figure = None; |
||
257 | if (figure is not None): |
||
258 | canvas_shift = len(figure.get_axes()); |
||
259 | cluster_figure = figure; |
||
260 | else: |
||
261 | cluster_figure = plt.figure(); |
||
262 | |||
263 | maximum_cols = self.__size_row; |
||
264 | maximum_rows = math.ceil( (self.__number_canvases + canvas_shift) / maximum_cols); |
||
265 | |||
266 | grid_spec = gridspec.GridSpec(maximum_rows, maximum_cols); |
||
267 | |||
268 | for index_canvas in range(len(self.__canvas_clusters)): |
||
269 | canvas_data = self.__canvas_clusters[index_canvas]; |
||
270 | dimension = self.__canvas_dimensions[index_canvas]; |
||
271 | |||
272 | #ax = axes[real_index]; |
||
273 | if ( (dimension == 1) or (dimension == 2) ): |
||
274 | ax = cluster_figure.add_subplot(grid_spec[index_canvas + canvas_shift]); |
||
275 | else: |
||
276 | ax = cluster_figure.add_subplot(grid_spec[index_canvas + canvas_shift], projection='3d'); |
||
277 | |||
278 | if (len(canvas_data) == 0): |
||
279 | plt.setp(ax, visible = False); |
||
280 | |||
281 | for cluster_descr in canvas_data: |
||
282 | self.__draw_canvas_cluster(ax, dimension, cluster_descr); |
||
283 | |||
284 | for attribute_descr in cluster_descr.attributes: |
||
285 | self.__draw_canvas_cluster(ax, dimension, attribute_descr); |
||
286 | |||
287 | if (visible_axis is True): |
||
288 | ax.xaxis.set_ticklabels([]); |
||
289 | ax.yaxis.set_ticklabels([]); |
||
290 | |||
291 | if (dimension == 3): |
||
292 | ax.zaxis.set_ticklabels([]); |
||
293 | |||
294 | if (self.__canvas_titles[index_canvas] is not None): |
||
295 | ax.set_title(self.__canvas_titles[index_canvas]); |
||
296 | |||
297 | ax.grid(visible_grid); |
||
298 | |||
299 | if (display is True): |
||
300 | plt.show(); |
||
301 | |||
302 | return cluster_figure; |
||
303 | |||
304 | |||
305 | """! |
||
306 | @brief Draw canvas cluster descriptor. |
||
307 | |||
308 | @param[in] ax (Axis): Axis of the canvas where canvas cluster descriptor should be displayed. |
||
309 | @param[in] dimension (uint): Canvas dimension. |
||
310 | @param[in] cluster_descr (canvas_cluster_descr): Canvas cluster descriptor that should be displayed. |
||
311 | |||
312 | @return (fig) Figure where clusters are shown. |
||
313 | |||
314 | """ |
||
315 | def __draw_canvas_cluster(self, ax, dimension, cluster_descr): |
||
316 | cluster = cluster_descr.cluster; |
||
317 | data = cluster_descr.data; |
||
318 | marker = cluster_descr.marker; |
||
319 | markersize = cluster_descr.markersize; |
||
320 | color = cluster_descr.color; |
||
321 | |||
322 | for item in cluster: |
||
323 | View Code Duplication | if (dimension == 1): |
|
|
|||
324 | if (data is None): |
||
325 | ax.plot(item[0], 0.0, color = color, marker = marker, markersize = markersize); |
||
326 | else: |
||
327 | ax.plot(data[item][0], 0.0, color = color, marker = marker, markersize = markersize); |
||
328 | |||
329 | elif (dimension == 2): |
||
330 | View Code Duplication | if (data is None): |
|
331 | ax.plot(item[0], item[1], color = color, marker = marker, markersize = markersize); |
||
332 | else: |
||
333 | ax.plot(data[item][0], data[item][1], color = color, marker = marker, markersize = markersize); |
||
334 | |||
335 | elif (dimension == 3): |
||
336 | if (data is None): |
||
337 | ax.scatter(item[0], item[1], item[2], c = color, marker = marker, s = markersize); |
||
338 | else: |
||
339 | ax.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker, s = markersize); |