Completed
Push — master ( 0d6080...7e0de7 )
by Andrei
52s
created

dynamic_visualizer.append_dynamics()   A

Complexity

Conditions 1

Size

Total Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
"""!
2
3
@brief Output dynamic visualizer
4
5
@authors Andrei Novikov ([email protected])
6
@date 2014-2018
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
27
import matplotlib.pyplot as plt;
0 ignored issues
show
Configuration introduced by
The import matplotlib.pyplot could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
28
29
from pyclustering.utils import set_ax_param;
30
31
32
class canvas_descr:
33
    """!
34
    @brief Describes plot where dynamic is displayed.
35
    @details Used by 'dynamic_visualizer' class.
36
37
    """
38
39
    def __init__(self, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True):
40
        """!
41
        @brief Constructor of canvas.
42
43
        @param[in] x_title (string): Title for X axis, if 'None', then nothing is displayed.
44
        @param[in] y_title (string): Title for Y axis, if 'None', then nothing is displayed.
45
        @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then
46
                    borders are calculated automatically.
47
        @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated
48
                    automatically.
49
        @param[in] x_labels (bool): If True then labels of X axis are displayed.
50
        @param[in] y_labels (bool): If True then labels of Y axis are displayed.
51
52
        """
53
54
        ## Title for X axis.
55
        self.x_title  = x_title;
56
57
        ## Title for Y axis.
58
        self.y_title  = y_title;
59
60
        ## Borders of X axis.
61
        self.x_lim    = x_lim;
62
63
        ## Borders of Y axis.
64
        self.y_lim    = y_lim;
65
66
        ## Defines whether X label should be displayed.
67
        self.x_labels = x_labels;
68
69
        ## Defines whether Y label should be displayed.
70
        self.y_labels = y_labels;
71
72
73
class dynamic_descr:
74
    """!
75
    @brief Output dynamic description that used to display.
76
    @details Used by 'dynamic_visualizer' class.
77
78
    """
79
80
    def __init__(self, canvas, time, dynamics, separate, color):
81
        """!
82
        @brief Constructor of output dynamic descriptor.
83
84
        @param[in] canvas (uint): Index of canvas where dynamic should be displayed, in case of 'separate'
85
                    representation this argument is considered as a first canvas from that displaying should be done.
86
        @param[in] time (list): Time points that are considered as a X axis.
87
        @param[in] dynamics (list): Dynamic or dynamics that should be displayed.
88
        @param[in] separate (bool|list): If 'True' then each dynamic is displayed on separate canvas, if it is defined
89
                    by list, for example, [ [1, 2], [3, 4] ], then the first and the second dynamics are displayed on
90
                    the canvas with index 'canvas' and the third and forth are displayed on the next 'canvas + 1'
91
                    canvas.
92
        @param[in] color (string): Color that is used to display output dynamic(s).
93
94
        """
95
96
        ## Index of canvas where (or from which) dynamic should be displayed.
97
        self.canvas     = canvas;
98
99
        ## Time points.
100
        self.time       = time;
101
102
        ## Dynamic or dynamics.
103
        self.dynamics   = dynamics;
104
105
        ## Defines how dynamic(s) should be displayed.
106
        self.separate   = self.__get_canonical_separate(separate);
107
108
        ## Color of dynamic.
109
        self.color      = color;
110
111
112
    def get_axis_index(self, index_dynamic):
113
        """!
114
        @brief Returns index of canvas where specified dynamic (by index 'index_dynamic') should be displayed.
115
116
        @param[in] index_dynamic (uint): Index of dynamic that should be displayed.
117
118
        @return (uint) Index of canvas.
119
120
        """
121
        return self.separate[index_dynamic];
122
123
124
    def __get_canonical_separate(self, input_separate):
125
        """!
126
        @brief Return unified representation of separation value.
127
        @details It represents list whose size is equal to amount of dynamics, where index of dynamic will show
128
                  where it should be displayed.
129
130
        @param[in] input_separate (bool|list): Input separate representation that should transformed.
131
132
        @return (list) Indexes where each dynamic should be displayed.
133
134
        """
135
        if (isinstance(input_separate, list)):
136
            separate = [0] * len(self.dynamics[0]);
137
            for canvas_index in range(len(input_separate)):
138
                dynamic_indexes = input_separate[canvas_index];
139
                for dynamic_index in dynamic_indexes:
140
                    separate[dynamic_index] = canvas_index;
141
            
142
            return separate;
143
        
144
        elif (input_separate is False):
145
            if (isinstance(self.dynamics[0], list) is True):
146
                return [ self.canvas ] * len(self.dynamics[0]);
147
            else:
148
                return [ self.canvas ];
149
        
150
        elif (input_separate is True):
151
            if (isinstance(self.dynamics[0], list) is True):
152
                return range(self.canvas, self.canvas + len(self.dynamics[0]));
153
            else:
154
                return [ self.canvas ];
155
156
        else:
157
            raise Exception("Incorrect type of argument 'separate' '%s'." % type(input_separate));
158
159
160
class dynamic_visualizer:
161
    """!
162
    @brief Basic output dynamic visualizer.
163
    @details The aim of the visualizer is to displayed output dynamic of any process, for example, output dynamic of
164
              oscillatory network.
165
166
    """
167
168
    def __init__(self, canvas, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True):
169
        """!
170
        @brief Construct dynamic visualizer.
171
        @details Default properties that are generalized in the constructor, for example, X axis title, can be
172
                  changed by corresponding method: 'set_canvas_properties'.
173
174
        @param[in] canvas (uint): Amount of canvases that is used for visualization.
175
        @param[in] x_title (string): Title for X axis of canvases, if 'None', then nothing is displayed.
176
        @param[in] y_title (string): Title for Y axis of canvases, if 'None', then nothing is displayed.
177
        @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then
178
                    borders are calculated automatically.
179
        @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated
180
                    automatically.
181
        @param[in] x_labels (bool): If True then labels of X axis are displayed.
182
        @param[in] y_labels (bool): If True then labels of Y axis are displayed.
183
184
        """
185
        self.__size = canvas;
186
        self.__canvases = [ canvas_descr(x_title, y_title, x_lim, y_lim, x_labels, y_labels) for _ in range(canvas) ];
187
        self.__dynamic_storage = [];
188
189
190
    def set_canvas_properties(self, canvas, x_title=None, y_title=None, x_lim=None, y_lim=None, x_labels=True, y_labels=True):
191
        """!
192
        @brief Set properties for specified canvas.
193
194
        @param[in] canvas (uint): Index of canvas whose properties should changed.
195
        @param[in] x_title (string): Title for X axis, if 'None', then nothing is displayed.
196
        @param[in] y_title (string): Title for Y axis, if 'None', then nothing is displayed.
197
        @param[in] x_lim (list): Defines borders of X axis like [from, to], for example [0, 3.14], if 'None' then
198
                    borders are calculated automatically.
199
        @param[in] y_lim (list): Defines borders of Y axis like [from, to], if 'None' then borders are calculated
200
                    automatically.
201
        @param[in] x_labels (bool): If True then labels of X axis are displayed.
202
        @param[in] y_labels (bool): If True then labels of Y axis are displayed.
203
204
        """
205
        self.__canvases[canvas] = canvas_descr(x_title, y_title, x_lim, y_lim, x_labels, y_labels);
206
207
208
    def append_dynamic(self, t, dynamic, canvas=0, color='blue'):
209
        """!
210
        @brief Append single dynamic to specified canvas (by default to the first with index '0').
211
212
        @param[in] t (list): Time points that corresponds to dynamic values and considered on a X axis.
213
        @param[in] dynamic (list): Value points of dynamic that are considered on an Y axis.
214
        @param[in] canvas (uint): Canvas where dynamic should be displayed.
215
        @param[in] color (string): Color that is used for drawing dynamic on the canvas.
216
217
        """
218
        description = dynamic_descr(canvas, t, dynamic, False, color);
219
        self.__dynamic_storage.append(description);
220
        self.__update_canvas_xlim(description.time, description.separate);
221
222
223
    def append_dynamics(self, t, dynamics, canvas=0, separate=False, color='blue'):
224
        """!
225
        @brief Append several dynamics to canvas or canvases (defined by 'canvas' and 'separate' arguments).
226
227
        @param[in] t (list): Time points that corresponds to dynamic values and considered on a X axis.
228
        @param[in] dynamics (list): Dynamics where each of them is considered on Y axis.
229
        @param[in] canvas (uint): Index of canvas where dynamic should be displayed, in case of 'separate'
230
                    representation this argument is considered as a first canvas from that displaying should be done.
231
        @param[in] separate (bool|list): If 'True' then each dynamic is displayed on separate canvas, if it is defined
232
                    by list, for example, [ [1, 2], [3, 4] ], then the first and the second dynamics are displayed on
233
                    the canvas with index 'canvas' and the third and forth are displayed on the next 'canvas + 1'
234
                    canvas.
235
        @param[in] color (string): Color that is used to display output dynamic(s).
236
237
        """
238
        description = dynamic_descr(canvas, t, dynamics, separate, color);
239
        self.__dynamic_storage.append(description);
240
        self.__update_canvas_xlim(description.time, description.separate);
241
242
243
    def show(self):
244
        """!
245
        @brief Draw and show output dynamics.
246
247
        """
248
        (_, axis) = plt.subplots(self.__size, 1);
249
        
250
        self.__format_canvases(axis);
251
        
252
        for dynamic in self.__dynamic_storage:
253
            self.__display_dynamic(axis, dynamic);
254
        
255
        plt.show();
256
257
258
    def __display_dynamic(self, axis, dyn_descr):
259
        if (isinstance(dyn_descr.dynamics[0], list) is True):
260
            self.__display_multiple_dynamic(axis, dyn_descr);
261
        
262
        else:
263
            self.__display_single_dynamic(axis, dyn_descr);
264
265
266
    def __display_multiple_dynamic(self, axis, dyn_descr):
267
        num_items = len(dyn_descr.dynamics[0]);
268
        for index in range(0, num_items, 1):
269
            y = [item[index] for item in dyn_descr.dynamics];
270
            
271
            axis_index = dyn_descr.get_axis_index(index);
272
            ax = self.__get_axis(axis, axis_index);
273
            
274
            ax.plot(dyn_descr.time, y, 'b-', linewidth = 0.5);
275
276
277
    def __display_single_dynamic(self, axis, dyn_descr):
278
        ax = self.__get_axis(axis, dyn_descr.canvas);
279
        ax.plot(dyn_descr.time, dyn_descr.dynamics, 'b-', linewidth = 0.5);
280
281
282
    def __format_canvases(self, axis):
283
        for index in range(self.__size):
284
            canvas = self.__canvases[index];
285
            
286
            ax = self.__get_axis(axis, index);
287
            set_ax_param(ax, canvas.x_title, canvas.y_title, canvas.x_lim, canvas.y_lim, canvas.x_labels, canvas.y_labels, True);
288
            
289
            if ( (len(self.__canvases) > 1) and (index != len(self.__canvases) - 1) ):
290
                ax.get_xaxis().set_visible(False);
291
292
293
    def __update_canvas_xlim(self, t, separate):
294
        for index in separate:
295
            self.__update_single_canvas_xlim(index, t);
296
297
298
    def __update_single_canvas_xlim(self, canvas_index, t):
299
        dynamic_xlim = [0, t[len(t) - 1]];
300
        if ( (self.__canvases[canvas_index].x_lim is None) or (self.__canvases[canvas_index].x_lim < dynamic_xlim) ):
301
            self.__canvases[canvas_index].x_lim = dynamic_xlim;
302
303
304
    def __get_axis(self, axis, index):
305
        if (index >= len(self.__canvases)):
306
            raise Exception("Impossible to get axis with index '%d' - total number of canvases '%d'."
307
                            % index, len(self.__canvases));
308
        
309
        ax = axis;
310
        if (self.__size > 1):
311
            ax = axis[index];
312
        
313
        return ax;