Completed
Push — master ( c43c88...95ecf9 )
by Andrei
01:20
created

data_corners()   B

Complexity

Conditions 6

Size

Total Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
dl 0
loc 30
rs 7.5384
c 0
b 0
f 0
1
"""!
2
3
@brief Utils that are used by modules of pyclustering.
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 time;
27
import numpy;
28
29
from PIL import Image;
30
from numpy import array;
31
32
import matplotlib.pyplot as plt;
33
from mpl_toolkits.mplot3d import Axes3D;
34
35
from sys import platform as _platform;
36
    
37
38
def read_sample(filename):
39
    """!
40
    @brief Returns sample for cluster analysis.
41
    
42
    @param[in] filename (string): Path to file with data for cluster analysis.
43
    
44
    @return (list) Points where each point represented by list of coordinates.
45
    
46
    """
47
    
48
    file = open(filename, 'r');
49
50
    sample = [[float(val) for val in line.split()] for line in file];
51
    
52
    file.close();
53
    return sample;
54
55
56
def read_image(filename):
57
    """!
58
    @brief Returns image as N-dimension (depends on the input image) matrix, where one element of list describes pixel.
59
    
60
    @param[in] filename (string): Path to image.
61
    
62
    @return (list) Pixels where each pixel described by list of RGB-values.
63
    
64
    """
65
    
66
    image_source = Image.open(filename);
67
    data = [pixel for pixel in image_source.getdata()];
68
    
69
    del image_source;
70
    image_source = None;
71
    return data;
72
73
74
def rgb2gray(image_rgb_array):
75
    """!
76
    @brief Returns image as 1-dimension (gray colored) matrix, where one element of list describes pixel.
77
    @details Luma coding is used for transformation.
78
    
79
    @param[in] image_rgb_array (list): Image represented by RGB list.
80
    
81
    @return (list) Image as gray colored matrix, where one element of list describes pixel.
82
    
83
    @code
84
        colored_image = read_image(file_name);
85
        gray_image = rgb2gray(colored_image);
86
    @endcode
87
    
88
    @see read_image()
89
    
90
    """
91
    
92
    image_gray_array = [0.0] * len(image_rgb_array);
93
    for index in range(0, len(image_rgb_array), 1):
94
        image_gray_array[index] = float(image_rgb_array[index][0]) * 0.2989 + float(image_rgb_array[index][1]) * 0.5870 + float(image_rgb_array[index][2]) * 0.1140;
95
    
96
    return image_gray_array;
97
98
99
def average_neighbor_distance(points, num_neigh):
100
    """!
101
    @brief Returns average distance for establish links between specified number of nearest neighbors.
102
    
103
    @param[in] points (list): Input data, list of points where each point represented by list.
104
    @param[in] num_neigh (uint): Number of neighbors that should be used for distance calculation.
105
    
106
    @return (double) Average distance for establish links between 'num_neigh' in data set 'points'.
107
    
108
    """
109
    
110
    if (num_neigh > len(points) - 1):
111
        raise NameError('Impossible to calculate average distance to neighbors when number of object is less than number of neighbors.');
112
    
113
    dist_matrix = [ [ 0.0 for i in range(len(points)) ] for j in range(len(points)) ];
114
    for i in range(0, len(points), 1):
115
        for j in range(i + 1, len(points), 1):
116
            distance = euclidean_distance(points[i], points[j]);
117
            dist_matrix[i][j] = distance;
118
            dist_matrix[j][i] = distance;
119
            
120
        dist_matrix[i] = sorted(dist_matrix[i]);
121
122
    total_distance = 0;
123
    for i in range(0, len(points), 1):
124
        # start from 0 - first element is distance to itself.
125
        for j in range(0, num_neigh, 1):
126
            total_distance += dist_matrix[i][j + 1];
127
            
128
    return ( total_distance / (num_neigh * len(points)) );
129
130
131
def centroid(points, indexes = None):
132
    """!
133
    @brief Calculate centroid of input set of points. 
134
    
135
    @param[in] points (list): Set of points for centroid calculation.
136
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during centroid calculation.
137
    
138
    @return (list) centroid on the set of points where each element of list is corresponding to value in its dimension.
139
    
140
    """
141
    
142
    dimension = len(points[0]);
143
    centroid_value = [0.0] * dimension;
144
    
145
    range_points = None;
146
    if (indexes is None):
147
        range_points = range(len(points));
148
    else:
149
        range_points = indexes;
150
    
151
    for index_point in range_points:
152
        centroid_value = list_math_addition(centroid_value, points[index_point]);
153
    
154
    centroid_value = list_math_division_number(centroid_value, len(range_points));
155
    return centroid_value;
156
157
158
def median(points, indexes = None):
159
    """!
160
    @brief Calculate geometric median of input set of points using Euclidian distance. 
161
    
162
    @param[in] points (list): Set of points for median calculation.
163
    @param[in] indexes (list): Indexes of objects in input set of points that will be taken into account during median calculation.
164
    
165
    @return (uint) index of point in input set that corresponds to median.
166
    
167
    """
168
    
169
    index_median = None;
170
    distance = float('Inf');
171
    
172
    range_points = None;
173
    if (indexes is None):
174
        range_points = range(len(points));
175
    else:
176
        range_points = indexes;
177
    
178
    for index_candidate in range_points:
179
        distance_candidate = 0.0;
180
        for index in range_points:
181
            distance_candidate += euclidean_distance_sqrt(points[index_candidate], points[index]);
182
        
183
        if (distance_candidate < distance):
184
            distance = distance_candidate;
185
            index_median = index_candidate;
186
    
187
    return index_median;
188
    
189
190
def euclidean_distance(a, b):
191
    """!
192
    @brief Calculate Euclidian distance between vector a and b. 
193
    
194
    @param[in] a (list): The first vector.
195
    @param[in] b (list): The second vector.
196
    
197
    @return (double) Euclidian distance between two vectors.
198
    
199
    @note This function for calculation is faster then standard function in ~100 times!
200
    
201
    """
202
    
203
    distance = euclidean_distance_sqrt(a, b);
204
    return distance**(0.5);
205
206
207
def euclidean_distance_sqrt(a, b):
208
    """!
209
    @brief Calculate square Euclidian distance between vector a and b.
210
    
211
    @param[in] a (list): The first vector.
212
    @param[in] b (list): The second vector.
213
    
214
    @return (double) Square Euclidian distance between two vectors.
215
    
216
    """  
217
    
218
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
219
        return (a - b)**2.0;
220
        
221
    dimension = len(a);
222
    # assert len(a) == len(b);
223
    
224
    distance = 0.0;
225
    for i in range(0, dimension):
226
        distance += (a[i] - b[i])**2.0;
227
        
228
    return distance;
229
230
231
def manhattan_distance(a, b):
232
    """!
233
    @brief Calculate Manhattan distance between vector a and b.
234
    
235
    @param[in] a (list): The first cluster.
236
    @param[in] b (list): The second cluster.
237
    
238
    @return (double) Manhattan distance between two vectors.
239
    
240
    """
241
    
242
    if ( ((type(a) == float) and (type(b) == float)) or ((type(a) == int) and (type(b) == int)) ):
243
        return abs(a - b);
244
    
245
    distance = 0.0;
246
    dimension = len(a);
247
    
248
    for i in range(0, dimension):
249
        distance += abs(a[i] - b[i]);
250
    
251
    return distance;
252
253
254
def average_inter_cluster_distance(cluster1, cluster2, data = None):
255
    """!
256
    @brief Calculates average inter-cluster distance between two clusters.
257
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
258
             or by list of indexes of points from the data (represented by list of points), in this case 
259
             data should be specified.
260
             
261
    @param[in] cluster1 (list): The first cluster where each element can represent index from the data or object itself.
262
    @param[in] cluster2 (list): The second cluster where each element can represent index from the data or object itself.
263
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
264
               otherwise elements of cluster will be considered as points.
265
    
266
    @return (double) Average inter-cluster distance between two clusters.
267
    
268
    """
269
    
270
    distance = 0.0;
271
    
272
    if (data is None):
273
        for i in range(len(cluster1)):
274
            for j in range(len(cluster2)):
275
                distance += euclidean_distance_sqrt(cluster1[i], cluster2[j]);
276
    else:
277
        for i in range(len(cluster1)):
278
            for j in range(len(cluster2)):
279
                distance += euclidean_distance_sqrt(data[ cluster1[i] ], data[ cluster2[j] ]);
280
    
281
    distance /= float(len(cluster1) * len(cluster2));
282
    return distance ** 0.5;
283
284
285
def average_intra_cluster_distance(cluster1, cluster2, data = None):
286
    """!
287
    @brief Calculates average intra-cluster distance between two clusters.
288
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
289
             or by list of indexes of points from the data (represented by list of points), in this case 
290
             data should be specified.
291
    
292
    @param[in] cluster1 (list): The first cluster.
293
    @param[in] cluster2 (list): The second cluster.
294
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
295
               otherwise elements of cluster will be considered as points.
296
    
297
    @return (double) Average intra-cluster distance between two clusters.
298
    
299
    """
300
        
301
    distance = 0.0;
302
    
303
    for i in range(len(cluster1) + len(cluster2)):
304
        for j in range(len(cluster1) + len(cluster2)):
305
            first_point = None;
306
            second_point = None;
307
            
308
            if (data is None):
309
                # the first point
310
                if (i < len(cluster1)): first_point = cluster1[i];
311
                else: first_point = cluster2[i - len(cluster1)];
312
                
313
                # the second point
314
                if (j < len(cluster1)): second_point = cluster1[j];
315
                else: second_point = cluster2[j - len(cluster1)];
316
                
317
            else:
318
                # the first point
319
                if (i < len(cluster1)): first_point = data[ cluster1[i] ];
320
                else: first_point = data[ cluster2[i - len(cluster1)] ];
321
            
322
                if (j < len(cluster1)): second_point = data[ cluster1[j] ];
323
                else: second_point = data[ cluster2[j - len(cluster1)] ];    
324
            
325
326
            
327
            distance += euclidean_distance_sqrt(first_point, second_point);
328
    
329
    distance /= float( (len(cluster1) + len(cluster2)) * (len(cluster1) + len(cluster2) - 1.0) );
330
    return distance ** 0.5;
331
332
333
def variance_increase_distance(cluster1, cluster2, data = None):
334
    """!
335
    @brief Calculates variance increase distance between two clusters.
336
    @details Clusters can be represented by list of coordinates (in this case data shouldn't be specified),
337
             or by list of indexes of points from the data (represented by list of points), in this case 
338
             data should be specified.
339
    
340
    @param[in] cluster1 (list): The first cluster.
341
    @param[in] cluster2 (list): The second cluster.
342
    @param[in] data (list): If specified than elements of clusters will be used as indexes,
343
               otherwise elements of cluster will be considered as points.
344
    
345
    @return (double) Average variance increase distance between two clusters.
346
    
347
    """
348
    
349
    # calculate local sum
350
    member_cluster1 = None;
351
    member_cluster2 = None;
352
    
353
    if (data is None):
354
        member_cluster1 = [0.0] * len(cluster1[0]);
355
        member_cluster2 = [0.0] * len(cluster2[0]);
356
        
357
    else:
358
        member_cluster1 = [0.0] * len(data[0]);
359
        member_cluster2 = [0.0] * len(data[0]);
360
    
361
    for i in range(len(cluster1)):
362
        if (data is None):
363
            member_cluster1 = list_math_addition(member_cluster1, cluster1[i]);
364
        else:
365
            member_cluster1 = list_math_addition(member_cluster1, data[ cluster1[i] ]);
366
    
367
    
368
    for j in range(len(cluster2)):
369
        if (data is None):
370
            member_cluster2 = list_math_addition(member_cluster2, cluster2[j]);
371
        else:
372
            member_cluster2 = list_math_addition(member_cluster2, data[ cluster2[j] ]);
373
    
374
    member_cluster_general = list_math_addition(member_cluster1, member_cluster2);
375
    member_cluster_general = list_math_division_number(member_cluster_general, len(cluster1) + len(cluster2));
376
    
377
    member_cluster1 = list_math_division_number(member_cluster1, len(cluster1));
378
    member_cluster2 = list_math_division_number(member_cluster2, len(cluster2));
379
    
380
    # calculate global sum
381
    distance_general = 0.0;
382
    distance_cluster1 = 0.0;
383
    distance_cluster2 = 0.0;
384
    
385
    for i in range(len(cluster1)):
386
        if (data is None):
387
            distance_cluster1 += euclidean_distance_sqrt(cluster1[i], member_cluster1);
388
            distance_general += euclidean_distance_sqrt(cluster1[i], member_cluster_general);
389
            
390
        else:
391
            distance_cluster1 += euclidean_distance_sqrt(data[ cluster1[i] ], member_cluster1);
392
            distance_general += euclidean_distance_sqrt(data[ cluster1[i] ], member_cluster_general);
393
    
394
    for j in range(len(cluster2)):
395
        if (data is None):
396
            distance_cluster2 += euclidean_distance_sqrt(cluster2[j], member_cluster2);
397
            distance_general += euclidean_distance_sqrt(cluster2[j], member_cluster_general);
398
            
399
        else:
400
            distance_cluster2 += euclidean_distance_sqrt(data[ cluster2[j] ], member_cluster2);
401
            distance_general += euclidean_distance_sqrt(data[ cluster2[j] ], member_cluster_general);
402
    
403
    return distance_general - distance_cluster1 - distance_cluster2;
404
405
406
def data_corners(data, data_filter = None):
407
    """!
408
    @brief Finds maximum and minimum corner in each dimension of the specified data.
409
    
410
    @param[in] data (list): List of points that should be analysed.
411
    @param[in] data_filter (list): List of indexes of the data that should be analysed,
412
                if it is 'None' then whole 'data' is analysed to obtain corners.
413
    
414
    @return (list) Tuple of two points that corresponds to minimum and maximum corner (min_corner, max_corner).
415
    
416
    """
417
    
418
    dimensions = len(data[0]);
419
    
420
    bypass = data_filter;
421
    if (bypass is None):
422
        bypass = range(len(data));
423
    
424
    maximum_corner = data[bypass[0]][:];
425
    minimum_corner = data[bypass[0]][:];
426
    
427
    for index_point in bypass:
428
        for index_dimension in range(dimensions):
429
            if (data[index_point][index_dimension] > maximum_corner[index_dimension]):
430
                maximum_corner[index_dimension] = data[index_point][index_dimension];
431
            
432
            if (data[index_point][index_dimension] < minimum_corner[index_dimension]):
433
                minimum_corner[index_dimension] = data[index_point][index_dimension];
434
    
435
    return (minimum_corner, maximum_corner);
436
437
438
def heaviside(value):
439
    """!
440
    @brief Calculates Heaviside function that represents step function.
441
    @details If input value is greater than 0 then returns 1, otherwise returns 0.
442
    
443
    @param[in] value (double): Argument of Heaviside function.
444
    
445
    @return (double) Value of Heaviside function.
446
    
447
    """
448
    if (value > 0.0): 
449
        return 1.0;
450
    
451
    return 0.0;
452
453
454
def timedcall(executable_function, *args):
455
    """!
456
    @brief Executes specified method or function with measuring of execution time.
457
    
458
    @param[in] executable_function (pointer): Pointer to function or method.
459
    @param[in] args (*): Arguments of called function or method.
460
    
461
    @return (tuple) Execution time and result of execution of function or method (execution_time, result_execution).
462
    
463
    """
464
    
465
    time_start = time.clock();
466
    result = executable_function(*args);
467
    time_end = time.clock();
468
    
469
    return (time_end - time_start, result);
470
471
472
def extract_number_oscillations(osc_dyn, index = 0, amplitude_threshold = 1.0):
473
    """!
474
    @brief Extracts number of oscillations of specified oscillator.
475
    
476
    @param[in] osc_dyn (list): Dynamic of oscillators.
477
    @param[in] index (uint): Index of oscillator in dynamic.
478
    @param[in] amplitude_threshold (double): Amplitude threshold, when oscillator value is greater than threshold then
479
               oscillation is incremented.
480
    
481
    @return (uint) Number of oscillations of specified oscillator.
482
    
483
    """
484
    
485
    number_oscillations = 0;
486
    high_level_trigger = False;
487
    
488
    for values in osc_dyn:
489
        if ( (values[index] > amplitude_threshold) and (high_level_trigger is False) ):
490
            number_oscillations += 1;
491
            high_level_trigger = True;
492
        
493
        elif ( (values[index] < amplitude_threshold) and (high_level_trigger is True) ):
494
            high_level_trigger = False;
495
            
496
    return number_oscillations;
497
498
499
def allocate_sync_ensembles(dynamic, tolerance = 0.1, threshold = 1.0, ignore = None):
500
    """!
501
    @brief Allocate clusters in line with ensembles of synchronous oscillators where each
502
           synchronous ensemble corresponds to only one cluster.
503
    
504
    @param[in] dynamic (dynamic): Dynamic of each oscillator.
505
    @param[in] tolerance (double): Maximum error for allocation of synchronous ensemble oscillators.
506
    @param[in] threshold (double): Amlitude trigger when spike is taken into account.
507
    @param[in] ignore (bool): Set of indexes that shouldn't be taken into account.
508
    
509
    @return (list) Grours (lists) of indexes of synchronous oscillators, for example, 
510
            [ [index_osc1, index_osc3], [index_osc2], [index_osc4, index_osc5] ].
511
            
512
    """
513
    
514
    descriptors = [] * len(dynamic);
515
    
516
    # Check from the end for obtaining result
517
    for index_dyn in range(0, len(dynamic[0]), 1):
518
        if ((ignore is not None) and (index_dyn in ignore)):
519
            continue;
520
        
521
        time_stop_simulation = len(dynamic) - 1;
522
        active_state = False;
523
        
524
        if (dynamic[time_stop_simulation][index_dyn] > threshold):
525
            active_state = True;
526
            
527
        # if active state is detected, it means we don't have whole oscillatory period for the considered oscillator, should be skipped.
528
        if (active_state is True):
529
            while ( (dynamic[time_stop_simulation][index_dyn] > threshold) and (time_stop_simulation > 0) ):
530
                time_stop_simulation -= 1;
531
            
532
            # if there are no any oscillation than let's consider it like noise
533
            if (time_stop_simulation == 0):
534
                continue;
535
            
536
            # reset
537
            active_state = False;
538
        
539
        desc = [0, 0, 0]; # end, start, average time of oscillation
540
        for t in range(time_stop_simulation, 0, -1):
541
            if ( (dynamic[t][index_dyn] > 0) and (active_state is False) ):
542
                desc[0] = t;
543
                active_state = True;
544
            elif ( (dynamic[t][index_dyn] < 0) and (active_state is True) ):
545
                desc[1] = t;
546
                active_state = False;
547
                
548
                break;
549
        
550
        if (desc == [0, 0, 0]):
551
            continue;
552
        
553
        desc[2] = desc[1] + (desc[0] - desc[1]) / 2.0;
554
        descriptors.append(desc);
555
        
556
    
557
    # Cluster allocation
558
    sync_ensembles = [];
559
    desc_sync_ensembles = [];
560
    
561
    for index_desc in range(0, len(descriptors), 1):
562
        if (descriptors[index_desc] == []):
563
            continue;
564
        
565
        if (len(sync_ensembles) == 0):
566
            desc_ensemble = descriptors[index_desc];
567
            reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance;
568
            
569
            desc_ensemble[0] = desc_ensemble[2] + reducer;
570
            desc_ensemble[1] = desc_ensemble[2] - reducer;
571
            
572
            desc_sync_ensembles.append(desc_ensemble);
573
            sync_ensembles.append([ index_desc ]);
574
        else:
575
            oscillator_captured = False;
576
            for index_ensemble in range(0, len(sync_ensembles), 1):
577
                if ( (desc_sync_ensembles[index_ensemble][0] > descriptors[index_desc][2]) and (desc_sync_ensembles[index_ensemble][1] < descriptors[index_desc][2])):
578
                    sync_ensembles[index_ensemble].append(index_desc);
579
                    oscillator_captured = True;
580
                    break;
581
                
582
            if (oscillator_captured is False):
583
                desc_ensemble = descriptors[index_desc];
584
                reducer = (desc_ensemble[0] - desc_ensemble[1]) * tolerance;
585
        
586
                desc_ensemble[0] = desc_ensemble[2] + reducer;
587
                desc_ensemble[1] = desc_ensemble[2] - reducer;
588
        
589
                desc_sync_ensembles.append(desc_ensemble);
590
                sync_ensembles.append([ index_desc ]);
591
    
592
    return sync_ensembles;
593
    
594
    
595
def draw_clusters(data, clusters, noise = [], marker_descr = '.', hide_axes = False, axes = None, display_result = True):
596
    """!
597
    @brief Displays clusters for data in 2D or 3D.
598
    
599
    @param[in] data (list): Points that are described by coordinates represented.
600
    @param[in] clusters (list): Clusters that are represented by lists of indexes where each index corresponds to point in data.
601
    @param[in] noise (list): Points that are regarded to noise.
602
    @param[in] marker_descr (string): Marker for displaying points.
603
    @param[in] hide_axes (bool): If True - axes is not displayed.
604
    @param[in] axes (ax) Matplotlib axes where clusters should be drawn, if it is not specified (None) then new plot will be created.
605
    @param[in] display_result (bool): If specified then matplotlib axes will be used for drawing and plot will not be shown.
606
    
607
    @return (ax) Matplotlib axes where drawn clusters are presented.
608
    
609
    """
610
    # Get dimension
611
    dimension = 0;
612
    if ( (data is not None) and (clusters is not None) ):
613
        dimension = len(data[0]);
614
    elif ( (data is None) and (clusters is not None) ):
615
        dimension = len(clusters[0][0]);
616
    else:
617
        raise NameError('Data or clusters should be specified exactly.');
618
    
619
    "Draw clusters"
620
    colors = [ 'red', 'blue', 'darkgreen', 'brown', 'violet', 
621
               'deepskyblue', 'darkgrey', 'lightsalmon', 'deeppink', 'yellow',
622
               'black', 'mediumspringgreen', 'orange', 'darkviolet', 'darkblue',
623
               'silver', 'lime', 'pink', 'gold', 'bisque' ];
624
               
625
    if (len(clusters) > len(colors)):
626
        raise NameError('Impossible to represent clusters due to number of specified colors.');
627
    
628
    fig = plt.figure();
629
    
630
    if (axes is None):
631
        # Check for dimensions
632
        if ((dimension) == 1 or (dimension == 2)):
633
            axes = fig.add_subplot(111);
634
        elif (dimension == 3):
635
            axes = fig.gca(projection='3d');
636
        else:
637
            raise NameError('Drawer supports only 2d and 3d data representation');
638
    
639
    color_index = 0;
640
    for cluster in clusters:
641
        color = colors[color_index];
642
        for item in cluster:
643
            if (dimension == 1):
644
                if (data is None):
645
                    axes.plot(item[0], 0.0, color = color, marker = marker_descr);
646
                else:
647
                    axes.plot(data[item][0], 0.0, color = color, marker = marker_descr);
648
            
649
            if (dimension == 2):
650
                if (data is None):
651
                    axes.plot(item[0], item[1], color = color, marker = marker_descr);
652
                else:
653
                    axes.plot(data[item][0], data[item][1], color = color, marker = marker_descr);
654
                    
655
            elif (dimension == 3):
656 View Code Duplication
                if (data is None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
657
                    axes.scatter(item[0], item[1], item[2], c = color, marker = marker_descr);
658
                else:
659
                    axes.scatter(data[item][0], data[item][1], data[item][2], c = color, marker = marker_descr);
660
        
661
        color_index += 1;
662
    
663
    for item in noise:
664
        if (dimension == 1):
665
            if (data is None):
666
                axes.plot(item[0], 0.0, 'w' + marker_descr);
667
            else:
668
                axes.plot(data[item][0], 0.0, 'w' + marker_descr);
669
670
        if (dimension == 2):
671
            if (data is None):
672
                axes.plot(item[0], item[1], 'w' + marker_descr);
673
            else:
674
                axes.plot(data[item][0], data[item][1], 'w' + marker_descr);
675
                
676
        elif (dimension == 3):
677 View Code Duplication
            if (data is None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
678
                axes.scatter(item[0], item[1], item[2], c = 'w', marker = marker_descr);
679
            else:
680
                axes.scatter(data[item][0], data[item][1], data[item][2], c = 'w', marker = marker_descr);
681
    
682
    axes.grid(True);
683
    
684
    if (hide_axes is True):
685
        axes.xaxis.set_ticklabels([]);
686
        axes.yaxis.set_ticklabels([]);
687
        
688
        if (dimension == 3):
689
            axes.zaxis.set_ticklabels([]);
690
    
691
    if (display_result is True):
692
        plt.show();
693
694
    return axes;
695
696
697
def draw_dynamics(t, dyn, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, separate = False, axes = None):
698
    """!
699
    @brief Draw dynamics of neurons (oscillators) in the network.
700
    @details It draws if matplotlib is not specified (None), othewise it should be performed manually.
701
    
702
    @param[in] t (list): Values of time (used by x axis).
703
    @param[in] dyn (list): Values of output of oscillators (used by y axis).
704
    @param[in] x_title (string): Title for Y.
705
    @param[in] y_title (string): Title for X.
706
    @param[in] x_lim (double): X limit.
707
    @param[in] y_lim (double): Y limit.
708
    @param[in] x_labels (bool): If True - shows X labels.
709
    @param[in] y_labels (bool): If True - shows Y labels.
710
    @param[in] separate (list): Consists of lists of oscillators where each such list consists of oscillator indexes that will be shown on separated stage.
711
    @param[in] axes (ax): If specified then matplotlib axes will be used for drawing and plot will not be shown.
712
    
713
    @return (ax) Axes of matplotlib.
714
    
715
    """
716
         
717
    number_lines = 0;
718
    
719
    if ( (isinstance(separate, bool) is True) and (separate is True) ):
720
        if (isinstance(dyn[0], list) is True):
721
            number_lines = len(dyn[0]);
722
        else:
723
            number_lines = 1;
724
            
725
    elif (isinstance(separate, list) is True):
726
        number_lines = len(separate);
727
        
728
    else:
729
        number_lines = 1;
730
    
731
    dysplay_result = False;
732
    if (axes is None):
733
        dysplay_result = True;
734
        (fig, axes) = plt.subplots(number_lines, 1);
735
    
736
    # Check if we have more than one dynamic
737
    if (isinstance(dyn[0], list) is True):
738
        num_items = len(dyn[0]);
739
        for index in range(0, num_items, 1):
740
            y = [item[index] for item in dyn];
741
            
742
            if (number_lines > 1):
743
                index_stage = -1;
744
                
745
                # Find required axes for the y
746
                if (isinstance(separate, bool) is True):
747
                    index_stage = index;
748
                    
749
                elif (isinstance(separate, list) is True):
750
                    for index_group in range(0, len(separate), 1):
751
                        if (index in separate[index_group]): 
752
                            index_stage = index_group;
753
                            break;
754
                
755
                if (index_stage != -1):
756
                    if (index_stage != number_lines - 1):
757
                        axes[index_stage].get_xaxis().set_visible(False);
758
                              
759
                    axes[index_stage].plot(t, y, 'b-', linewidth = 0.5); 
760
                    set_ax_param(axes[index_stage], x_title, y_title, x_lim, y_lim, x_labels, y_labels, True);
761
                
762
            else:
763
                axes.plot(t, y, 'b-', linewidth = 0.5);
764
                set_ax_param(axes, x_title, y_title, x_lim, y_lim, x_labels, y_labels, True);
765
    else:
766
        axes.plot(t, dyn, 'b-', linewidth = 0.5);     
767
        set_ax_param(axes, x_title, y_title, x_lim, y_lim, x_labels, y_labels, True);
768
    
769
    if (dysplay_result is True):
770
        plt.show();
771
    
772
    return axes;
773
774
775
def set_ax_param(ax, x_title = None, y_title = None, x_lim = None, y_lim = None, x_labels = True, y_labels = True, grid = True):
776
    """!
777
    @brief Sets parameters for matplotlib ax.
778
    
779
    @param[in] ax (Axes): Axes for which parameters should applied.
780
    @param[in] x_title (string): Title for Y.
781
    @param[in] y_title (string): Title for X.
782
    @param[in] x_lim (double): X limit.
783
    @param[in] y_lim (double): Y limit.
784
    @param[in] x_labels (bool): If True - shows X labels.
785
    @param[in] y_labels (bool): If True - shows Y labels.
786
    @param[in] grid (bool): If True - shows grid.
787
    
788
    """
789
    from matplotlib.font_manager import FontProperties;
790
    from matplotlib import rcParams;
791
    
792
    if (_platform == "linux") or (_platform == "linux2"):
793
        rcParams['font.sans-serif'] = ['Liberation Serif'];
794
    else:
795
        rcParams['font.sans-serif'] = ['Arial'];
796
        
797
    rcParams['font.size'] = 12;
798
        
799
    surface_font = FontProperties();
800
    if (_platform == "linux") or (_platform == "linux2"):
801
        surface_font.set_name('Liberation Serif');
802
    else:
803
        surface_font.set_name('Arial');
804
        
805
    surface_font.set_size('12');
806
    
807
    if (y_title is not None): ax.set_ylabel(y_title, fontproperties = surface_font);
808
    if (x_title is not None): ax.set_xlabel(x_title, fontproperties = surface_font);
809
    
810
    if (x_lim is not None): ax.set_xlim(x_lim[0], x_lim[1]);
811
    if (y_lim is not None): ax.set_ylim(y_lim[0], y_lim[1]);
812
    
813
    if (x_labels is False): ax.xaxis.set_ticklabels([]);
814
    if (y_labels is False): ax.yaxis.set_ticklabels([]);
815
    
816
    ax.grid(grid);
817
818
819
def draw_dynamics_set(dynamics, xtitle = None, ytitle = None, xlim = None, ylim = None, xlabels = False, ylabels = False):
820
    """!
821
    @brief Draw lists of dynamics of neurons (oscillators) in the network.
822
    
823
    @param[in] dynamics (list): List of network outputs that are represented by values of output of oscillators (used by y axis).
824
    @param[in] xtitle (string): Title for Y.
825
    @param[in] ytitle (string): Title for X.
826
    @param[in] xlim (double): X limit.
827
    @param[in] ylim (double): Y limit.
828
    @param[in] xlabels (bool): If True - shows X labels.
829
    @param[in] ylabels (bool): If True - shows Y labels.
830
    
831
    """
832
    # Calculate edge for confortable representation.
833
    number_dynamics = len(dynamics);
834
    
835
    number_cols = int(numpy.ceil(number_dynamics ** 0.5));
836
    number_rows = int(numpy.ceil(number_dynamics / number_cols));
837
    
838
839
    real_index = 0, 0;
840
    double_indexer = True;
841
    if ( (number_cols == 1) or (number_rows == 1) ):
842
        real_index = 0;
843
        double_indexer = False;
844
    
845
    (fig, axarr) = plt.subplots(number_rows, number_cols);
846
    #plt.setp([ax for ax in axarr], visible = False);
847
    
848
    for dynamic in dynamics:
849
        axarr[real_index] = draw_dynamics(dynamic[0], dynamic[1], xtitle, ytitle, xlim, ylim, xlabels, ylabels, axes = axarr[real_index]);
850
        #plt.setp(axarr[real_index], visible = True);
851
        
852
        if (double_indexer is True):
853
            real_index = real_index[0], real_index[1] + 1;
854
            if (real_index[1] >= number_cols):
855
                real_index = real_index[0] + 1, 0; 
856
        else:
857
            real_index += 1;
858
            
859
    plt.show();
860
861
862
def draw_image_color_segments(source, clusters, hide_axes = True):
863
    """!
864
    @brief Shows image segments using colored image.
865
    @details Each color on result image represents allocated segment. The first image is initial and other is result of segmentation.
866
    
867
    @param[in] source (string): Path to image.
868
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
869
                                consists of indexes of pixel from source image.
870
    @param[in] hide_axes (bool): If True then axes will not be displayed.
871
    
872
    """
873
        
874
    image_source = Image.open(source);
875
    image_size = image_source.size;
876
    
877
    (fig, axarr) = plt.subplots(1, 2);
878
    
879
    plt.setp([ax for ax in axarr], visible = False);
880
    
881
    available_colors = [ (0, 162, 232),   (34, 177, 76),   (237, 28, 36),
882
                         (255, 242, 0),   (0, 0, 0),       (237, 28, 36),
883
                         (255, 174, 201), (127, 127, 127), (185, 122, 87), 
884
                         (200, 191, 231), (136, 0, 21),    (255, 127, 39),
885
                         (63, 72, 204),   (195, 195, 195), (255, 201, 14),
886
                         (239, 228, 176), (181, 230, 29),  (153, 217, 234),
887
                         (112, 146, 180) ];
888
    
889
    image_color_segments = [(255, 255, 255)] * (image_size[0] * image_size[1]);
890
    
891
    for index_segment in range(len(clusters)):
892
        for index_pixel in clusters[index_segment]:
893
            image_color_segments[index_pixel] = available_colors[index_segment];
894
    
895
    stage = array(image_color_segments, numpy.uint8);
896
    stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)); # ((3),) it's size of RGB - third dimension.
897
    image_cluster = Image.fromarray(stage, 'RGB');
898
    
899
    axarr[0].imshow(image_source, interpolation = 'none');
900
    axarr[1].imshow(image_cluster, interpolation = 'none');
901
    
902
    for i in range(2):
903
        plt.setp(axarr[i], visible = True);
904
        
905
        if (hide_axes is True):
906
            axarr[i].xaxis.set_ticklabels([]);
907
            axarr[i].yaxis.set_ticklabels([]);
908
            axarr[i].xaxis.set_ticks_position('none');
909
            axarr[i].yaxis.set_ticks_position('none');
910
    
911
    plt.show();
912
913
914
def draw_image_mask_segments(source, clusters, hide_axes = True):
915
    """!
916
    @brief Shows image segments using black masks.
917
    @details Each black mask of allocated segment is presented on separate plot.
918
             The first image is initial and others are black masks of segments.
919
    
920
    @param[in] source (string): Path to image.
921
    @param[in] clusters (list): List of clusters (allocated segments of image) where each cluster
922
                                consists of indexes of pixel from source image.
923
    @param[in] hide_axes (bool): If True then axes will not be displayed.
924
    
925
    """
926
    if (len(clusters) == 0):
927
        print("Warning: Nothing to draw - list of clusters is empty.")
928
        return;
929
        
930
    image_source = Image.open(source);
931
    image_size = image_source.size;
932
    
933
    # Calculate edge for confortable representation.
934
    number_clusters = len(clusters) + 1; # show with the source image
935
    
936
    number_cols = int(numpy.ceil(number_clusters ** 0.5));
937
    number_rows = int(numpy.ceil(number_clusters / number_cols));
938
    
939
940
    real_index = 0, 0;
941
    double_indexer = True;
942
    if ( (number_cols == 1) or (number_rows == 1) ):
943
        real_index = 0;
944
        double_indexer = False;
945
    
946
    (fig, axarr) = plt.subplots(number_rows, number_cols);
947
    plt.setp([ax for ax in axarr], visible = False);
948
    
949
    axarr[real_index].imshow(image_source, interpolation = 'none');
950
    plt.setp(axarr[real_index], visible = True);
951
    
952
    if (hide_axes is True):
953
        axarr[real_index].xaxis.set_ticklabels([]);
954
        axarr[real_index].yaxis.set_ticklabels([]);
955
        axarr[real_index].xaxis.set_ticks_position('none');
956
        axarr[real_index].yaxis.set_ticks_position('none');
957
            
958
    if (double_indexer is True):
959
        real_index = 0, 1;
960
    else:
961
        real_index += 1;
962
    
963
    for cluster in clusters:
964
        stage_cluster = [(255, 255, 255)] * (image_size[0] * image_size[1]);
965
        for index in cluster:
966
            stage_cluster[index] = (0, 0, 0);
967
          
968
        stage = array(stage_cluster, numpy.uint8);
969
        stage = numpy.reshape(stage, (image_size[1], image_size[0]) + ((3),)); # ((3),) it's size of RGB - third dimension.
970
        
971
        image_cluster = Image.fromarray(stage, 'RGB');
972
        
973
        axarr[real_index].imshow(image_cluster, interpolation = 'none');
974
        plt.setp(axarr[real_index], visible = True);
975
        
976
        if (hide_axes is True):
977
            axarr[real_index].xaxis.set_ticklabels([]);
978
            axarr[real_index].yaxis.set_ticklabels([]);
979
            
980
            axarr[real_index].xaxis.set_ticks_position('none');
981
            axarr[real_index].yaxis.set_ticks_position('none');
982
        
983
        if (double_indexer is True):
984
            real_index = real_index[0], real_index[1] + 1;
985
            if (real_index[1] >= number_cols):
986
                real_index = real_index[0] + 1, 0; 
987
        else:
988
            real_index += 1;
989
990
            
991
    plt.show();
992
993
994
def linear_sum(list_vector):
995
    """!
996
    @brief Calculates linear sum of vector that is represented by list, each element can be represented by list - multidimensional elements.
997
    
998
    @param[in] list_vector (list): Input vector.
999
    
1000
    @return (list|double) Linear sum of vector that can be represented by list in case of multidimensional elements.
1001
    
1002
    """
1003
    dimension = 1;
1004
    linear_sum = 0.0;
1005
    list_representation = (type(list_vector[0]) == list);
1006
    
1007
    if (list_representation is True):
1008
        dimension = len(list_vector[0]);
1009
        linear_sum = [0] * dimension;
1010
        
1011
    for index_element in range(0, len(list_vector)):
1012
        if (list_representation is True):
1013
            for index_dimension in range(0, dimension):
1014
                linear_sum[index_dimension] += list_vector[index_element][index_dimension];
1015
        else:
1016
            linear_sum += list_vector[index_element];
1017
1018
    return linear_sum;
1019
1020
1021
def square_sum(list_vector):
1022
    """!
1023
    @brief Calculates square sum of vector that is represented by list, each element can be represented by list - multidimensional elements.
1024
    
1025
    @param[in] list_vector (list): Input vector.
1026
    
1027
    @return (double) Square sum of vector.
1028
    
1029
    """
1030
    
1031
    square_sum = 0.0;
1032
    list_representation = (type(list_vector[0]) == list);
1033
        
1034
    for index_element in range(0, len(list_vector)):
1035
        if (list_representation is True):
1036
            square_sum += sum(list_math_multiplication(list_vector[index_element], list_vector[index_element]));
1037
        else:
1038
            square_sum += list_vector[index_element] * list_vector[index_element];
1039
         
1040
    return square_sum;
1041
1042
    
1043
def list_math_subtraction(a, b):
1044
    """!
1045
    @brief Calculates subtraction of two lists.
1046
    @details Each element from list 'a' is subtracted by element from list 'b' accordingly.
1047
    
1048
    @param[in] a (list): List of elements that supports mathematical subtraction.
1049
    @param[in] b (list): List of elements that supports mathematical subtraction.
1050
    
1051
    @return (list) Results of subtraction of two lists.
1052
    
1053
    """
1054
    return [a[i] - b[i] for i in range(len(a))];
1055
1056
1057
def list_math_substraction_number(a, b):
1058
    """!
1059
    @brief Calculates subtraction between list and number.
1060
    @details Each element from list 'a' is subtracted by number 'b'.
1061
    
1062
    @param[in] a (list): List of elements that supports mathematical subtraction.
1063
    @param[in] b (list): Value that supports mathematical subtraction.
1064
    
1065
    @return (list) Results of subtraction between list and number.
1066
    
1067
    """        
1068
    return [a[i] - b for i in range(len(a))];  
1069
1070
1071
def list_math_addition(a, b):
1072
    """!
1073
    @brief Addition of two lists.
1074
    @details Each element from list 'a' is added to element from list 'b' accordingly.
1075
    
1076
    @param[in] a (list): List of elements that supports mathematic addition..
1077
    @param[in] b (list): List of elements that supports mathematic addition..
1078
    
1079
    @return (list) Results of addtion of two lists.
1080
    
1081
    """    
1082
    return [a[i] + b[i] for i in range(len(a))];
1083
1084
1085
def list_math_addition_number(a, b):
1086
    """!
1087
    @brief Addition between list and number.
1088
    @details Each element from list 'a' is added to number 'b'.
1089
    
1090
    @param[in] a (list): List of elements that supports mathematic addition.
1091
    @param[in] b (double): Value that supports mathematic addition.
1092
    
1093
    @return (list) Result of addtion of two lists.
1094
    
1095
    """    
1096
    return [a[i] + b for i in range(len(a))];
1097
1098
1099
def list_math_division_number(a, b):
1100
    """!
1101
    @brief Division between list and number.
1102
    @details Each element from list 'a' is divided by number 'b'.
1103
    
1104
    @param[in] a (list): List of elements that supports mathematic division.
1105
    @param[in] b (double): Value that supports mathematic division.
1106
    
1107
    @return (list) Result of division between list and number.
1108
    
1109
    """    
1110
    return [a[i] / b for i in range(len(a))];
1111
1112
1113
def list_math_division(a, b):
1114
    """!
1115
    @brief Division of two lists.
1116
    @details Each element from list 'a' is divided by element from list 'b' accordingly.
1117
    
1118
    @param[in] a (list): List of elements that supports mathematic division.
1119
    @param[in] b (list): List of elements that supports mathematic division.
1120
    
1121
    @return (list) Result of division of two lists.
1122
    
1123
    """    
1124
    return [a[i] / b[i] for i in range(len(a))];
1125
1126
1127
def list_math_multiplication_number(a, b):
1128
    """!
1129
    @brief Multiplication between list and number.
1130
    @details Each element from list 'a' is multiplied by number 'b'.
1131
    
1132
    @param[in] a (list): List of elements that supports mathematic division.
1133
    @param[in] b (double): Number that supports mathematic division.
1134
    
1135
    @return (list) Result of division between list and number.
1136
    
1137
    """    
1138
    return [a[i] * b for i in range(len(a))];
1139
1140
1141
def list_math_multiplication(a, b):
1142
    """!
1143
    @brief Multiplication of two lists.
1144
    @details Each element from list 'a' is multiplied by element from list 'b' accordingly.
1145
    
1146
    @param[in] a (list): List of elements that supports mathematic multiplication.
1147
    @param[in] b (list): List of elements that supports mathematic multiplication.
1148
    
1149
    @return (list) Result of multiplication of elements in two lists.
1150
    
1151
    """        
1152
    return [a[i] * b[i] for i in range(len(a))];
1153