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