controls/DebugVariablePanel/DebugVariableGraphicViewer.py
changeset 1267 fae0809eae98
parent 1264 27c8578670c8
child 1362 077bcba2d485
equal deleted inserted replaced
1266:4282f62c1cf0 1267:fae0809eae98
    57 COLOR_CYCLE = ['r', 'b', 'g', 'm', 'y', 'k']
    57 COLOR_CYCLE = ['r', 'b', 'g', 'm', 'y', 'k']
    58 # Color for graph cursor
    58 # Color for graph cursor
    59 CURSOR_COLOR = '#800080'
    59 CURSOR_COLOR = '#800080'
    60 
    60 
    61 #-------------------------------------------------------------------------------
    61 #-------------------------------------------------------------------------------
       
    62 #                      Debug Variable Graphic Viewer Helpers
       
    63 #-------------------------------------------------------------------------------
       
    64 
       
    65 def merge_ranges(ranges):
       
    66     """
       
    67     Merge variables data range in a list to return a range of minimal min range
       
    68     value and maximal max range value extended of 10% for keeping a padding
       
    69     around graph in canvas
       
    70     @param ranges: [(range_min_value, range_max_value),...]
       
    71     @return: merged_range_min_value, merged_range_max_value
       
    72     """
       
    73     # Get minimal and maximal range value
       
    74     min_value = max_value = None
       
    75     for range_min, range_max in ranges:
       
    76         # Update minimal range value
       
    77         if min_value is None:
       
    78             min_value = range_min
       
    79         elif range_min is not None:
       
    80             min_value = min(min_value, range_min)
       
    81         
       
    82         # Update maximal range value
       
    83         if max_value is None:
       
    84             max_value = range_max
       
    85         elif range_min is not None:
       
    86             max_value = max(max_value, range_max)
       
    87     
       
    88     # Calculate range center and width if at least one valid range is defined
       
    89     if min_value is not None and max_value is not None:
       
    90         center = (min_value + max_value) / 2.
       
    91         range_size = max(1.0, max_value - min_value)
       
    92     
       
    93     # Set default center and with if no valid range is defined
       
    94     else:
       
    95         center = 0.5
       
    96         range_size = 1.0
       
    97     
       
    98     # Return range expended from 10 %
       
    99     return center - range_size * 0.55, center + range_size * 0.55
       
   100 
       
   101 #-------------------------------------------------------------------------------
    62 #                   Debug Variable Graphic Viewer Drop Target
   102 #                   Debug Variable Graphic Viewer Drop Target
    63 #-------------------------------------------------------------------------------
   103 #-------------------------------------------------------------------------------
    64 
   104 
    65 """
   105 """
    66 Class that implements a custom drop target class for Debug Variable Graphic
   106 Class that implements a custom drop target class for Debug Variable Graphic
   222         # List of current displayed contextual buttons
   262         # List of current displayed contextual buttons
   223         self.ContextualButtons = []
   263         self.ContextualButtons = []
   224         # Reference to item for which contextual buttons was displayed
   264         # Reference to item for which contextual buttons was displayed
   225         self.ContextualButtonsItem = None
   265         self.ContextualButtonsItem = None
   226         
   266         
       
   267         # Flag indicating that zoom fit current displayed data range or whole
       
   268         # data range if False
       
   269         self.ZoomFit = False
       
   270         
   227         # Create figure for drawing graphs
   271         # Create figure for drawing graphs
   228         self.Figure = matplotlib.figure.Figure(facecolor='w')
   272         self.Figure = matplotlib.figure.Figure(facecolor='w')
   229         # Defined border around figure in canvas
   273         # Defined border around figure in canvas
   230         self.Figure.subplotpars.update(top=0.95, left=0.1, 
   274         self.Figure.subplotpars.update(top=0.95, left=0.1, 
   231                                        bottom=0.1, right=0.95)
   275                                        bottom=0.1, right=0.95)
   253         self.mpl_connect('button_press_event', self.OnCanvasButtonPressed)
   297         self.mpl_connect('button_press_event', self.OnCanvasButtonPressed)
   254         self.mpl_connect('motion_notify_event', self.OnCanvasMotion)
   298         self.mpl_connect('motion_notify_event', self.OnCanvasMotion)
   255         self.mpl_connect('button_release_event', self.OnCanvasButtonReleased)
   299         self.mpl_connect('button_release_event', self.OnCanvasButtonReleased)
   256         self.mpl_connect('scroll_event', self.OnCanvasScroll)
   300         self.mpl_connect('scroll_event', self.OnCanvasScroll)
   257         
   301         
       
   302         # Add buttons for zooming on current displayed data range
       
   303         self.Buttons.append(
       
   304                 GraphButton(0, 0, "fit_graph", self.OnZoomFitButton))
       
   305         
   258         # Add buttons for changing canvas size with predefined height
   306         # Add buttons for changing canvas size with predefined height
   259         for size, bitmap in zip(
   307         for size, bitmap in zip(
   260                 [SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI],
   308                 [SIZE_MINI, SIZE_MIDDLE, SIZE_MAXI],
   261                 ["minimize_graph", "middle_graph", "maximize_graph"]):
   309                 ["minimize_graph", "middle_graph", "maximize_graph"]):
   262             self.Buttons.append(
   310             self.Buttons.append(
   301         Set cursor tick
   349         Set cursor tick
   302         @param cursor_tick: Cursor tick
   350         @param cursor_tick: Cursor tick
   303         """
   351         """
   304         self.CursorTick = cursor_tick
   352         self.CursorTick = cursor_tick
   305     
   353     
       
   354     def SetZoomFit(self, zoom_fit):
       
   355         """
       
   356         Set flag indicating that zoom fit current displayed data range
       
   357         @param zoom_fit: Flag for zoom fit (False: zoom fit whole data range)
       
   358         """
       
   359         # Flag is different from the actual one 
       
   360         if zoom_fit != self.ZoomFit:
       
   361             # Save new flag value
       
   362             self.ZoomFit = zoom_fit
       
   363             
       
   364             # Update button for zoom fit bitmap
       
   365             self.Buttons[0].SetBitmap("full_graph" if zoom_fit else "fit_graph")
       
   366             
       
   367             # Refresh canvas
       
   368             self.RefreshViewer()
       
   369         
   306     def SubscribeAllDataConsumers(self):
   370     def SubscribeAllDataConsumers(self):
   307         """
   371         """
   308         Function that unsubscribe and remove every item that store values of
   372         Function that unsubscribe and remove every item that store values of
   309         a variable that doesn't exist in PLC anymore
   373         a variable that doesn't exist in PLC anymore
   310         """
   374         """
   311         DebugVariableViewer.SubscribeAllDataConsumers(self)
   375         DebugVariableViewer.SubscribeAllDataConsumers(self)
       
   376         
       
   377         # Graph still have data to display
   312         if not self.ItemsIsEmpty():
   378         if not self.ItemsIsEmpty():
       
   379             # Reset flag indicating that zoom fit current displayed data range
       
   380             self.SetZoomFit(False)
       
   381             
   313             self.ResetGraphics()
   382             self.ResetGraphics()
   314     
   383     
   315     def Is3DCanvas(self):
   384     def Is3DCanvas(self):
   316         """
   385         """
   317         Return if Viewer is a 3D canvas
   386         Return if Viewer is a 3D canvas
   425             [(item, [entry for entry in item.GetData()])
   494             [(item, [entry for entry in item.GetData()])
   426              for item in (self.Items 
   495              for item in (self.Items 
   427                           if item is None 
   496                           if item is None 
   428                           else [item])])
   497                           else [item])])
   429     
   498     
       
   499     def OnZoomFitButton(self):
       
   500         """
       
   501         Function called when Viewer Zoom Fit button is pressed
       
   502         """
       
   503         # Toggle zoom fit flag value
       
   504         self.SetZoomFit(not self.ZoomFit)
       
   505         
   430     def GetOnChangeSizeButton(self, height):
   506     def GetOnChangeSizeButton(self, height):
   431         """
   507         """
   432         Function that generate callback function for change Viewer height to
   508         Function that generate callback function for change Viewer height to
   433         pre-defined height button
   509         pre-defined height button
   434         @param height: Height that change Viewer to
   510         @param height: Height that change Viewer to
   492         items = self.ItemsDict.values()
   568         items = self.ItemsDict.values()
   493         
   569         
   494         # Graph is orthogonal
   570         # Graph is orthogonal
   495         if self.GraphType == GRAPH_ORTHOGONAL:
   571         if self.GraphType == GRAPH_ORTHOGONAL:
   496             # Extract items data displayed in canvas figure
   572             # Extract items data displayed in canvas figure
   497             min_start_tick = max(start_tick, self.GetItemsMinCommonTick())
   573             start_tick = max(start_tick, self.GetItemsMinCommonTick())
   498             start_tick = max(start_tick, min_start_tick)
   574             end_tick = max(end_tick, start_tick)
   499             end_tick = max(end_tick, min_start_tick)
       
   500             x_data = items[0].GetData(start_tick, end_tick)
   575             x_data = items[0].GetData(start_tick, end_tick)
   501             y_data = items[1].GetData(start_tick, end_tick)
   576             y_data = items[1].GetData(start_tick, end_tick)
   502             
   577             
   503             # Search for the nearest point from mouse position
   578             # Search for the nearest point from mouse position
   504             if len(x_data) > 0 and len(y_data) > 0:
   579             if len(x_data) > 0 and len(y_data) > 0:
   767     
   842     
   768     # Cursor tick move for each arrow key
   843     # Cursor tick move for each arrow key
   769     KEY_CURSOR_INCREMENT = {
   844     KEY_CURSOR_INCREMENT = {
   770         wx.WXK_LEFT: -1,
   845         wx.WXK_LEFT: -1,
   771         wx.WXK_RIGHT: 1,
   846         wx.WXK_RIGHT: 1,
   772         wx.WXK_UP: -10,
   847         wx.WXK_UP: 10,
   773         wx.WXK_DOWN: 10}
   848         wx.WXK_DOWN: -10}
   774     
   849     
   775     def OnKeyDown(self, event):
   850     def OnKeyDown(self, event):
   776         """
   851         """
   777         Function called when key is pressed
   852         Function called when key is pressed
   778         @param event: wx.KeyEvent
   853         @param event: wx.KeyEvent
  1041         
  1116         
  1042         # Update subplots
  1117         # Update subplots
  1043         self.Figure.subplots_adjust()
  1118         self.Figure.subplots_adjust()
  1044     
  1119     
  1045     def RefreshViewer(self, refresh_graphics=True):
  1120     def RefreshViewer(self, refresh_graphics=True):
  1046         
  1121         """
       
  1122         Function called to refresh displayed by matplotlib canvas
       
  1123         @param refresh_graphics: Flag indicating that graphs have to be
       
  1124         refreshed (False: only label values have to be refreshed)
       
  1125         """
       
  1126         # Refresh graphs if needed
  1047         if refresh_graphics:
  1127         if refresh_graphics:
       
  1128             # Get tick range of values to display
  1048             start_tick, end_tick = self.ParentWindow.GetRange()
  1129             start_tick, end_tick = self.ParentWindow.GetRange()
  1049             
  1130             
       
  1131             # Graph is parallel
  1050             if self.GraphType == GRAPH_PARALLEL:    
  1132             if self.GraphType == GRAPH_PARALLEL:    
  1051                 min_value = max_value = None
  1133                 # Init list of data range for each variable displayed
  1052                 
  1134                 ranges = []
       
  1135                 
       
  1136                 # Get data and range for each variable displayed
  1053                 for idx, item in enumerate(self.Items):
  1137                 for idx, item in enumerate(self.Items):
  1054                     data = item.GetData(start_tick, end_tick)
  1138                     data, min_value, max_value = item.GetDataAndValueRange(
       
  1139                                 start_tick, end_tick, not self.ZoomFit)
       
  1140                     
       
  1141                     # Check that data is not empty
  1055                     if data is not None:
  1142                     if data is not None:
  1056                         item_min_value, item_max_value = item.GetValueRange()
  1143                         # Add variable range to list of variable data range
  1057                         if min_value is None:
  1144                         ranges.append((min_value, max_value))
  1058                             min_value = item_min_value
       
  1059                         elif item_min_value is not None:
       
  1060                             min_value = min(min_value, item_min_value)
       
  1061                         if max_value is None:
       
  1062                             max_value = item_max_value
       
  1063                         elif item_max_value is not None:
       
  1064                             max_value = max(max_value, item_max_value)
       
  1065                         
  1145                         
       
  1146                         # Add plot to canvas if not yet created
  1066                         if len(self.Plots) <= idx:
  1147                         if len(self.Plots) <= idx:
  1067                             self.Plots.append(
  1148                             self.Plots.append(
  1068                                 self.Axes.plot(data[:, 0], data[:, 1])[0])
  1149                                 self.Axes.plot(data[:, 0], data[:, 1])[0])
       
  1150                         
       
  1151                         # Set data to already created plot in canvas
  1069                         else:
  1152                         else:
  1070                             self.Plots[idx].set_data(data[:, 0], data[:, 1])
  1153                             self.Plots[idx].set_data(data[:, 0], data[:, 1])
       
  1154                 
       
  1155                 # Get X and Y axis ranges
       
  1156                 x_min, x_max = start_tick, end_tick
       
  1157                 y_min, y_max = merge_ranges(ranges)
       
  1158                 
       
  1159                 # Display cursor in canvas if a cursor tick is defined and it is
       
  1160                 # include in values tick range
       
  1161                 if (self.CursorTick is not None and 
       
  1162                     start_tick <= self.CursorTick <= end_tick):
  1071                     
  1163                     
  1072                 if min_value is not None and max_value is not None:
  1164                     # Define a vertical line to display cursor position if no
  1073                     y_center = (min_value + max_value) / 2.
  1165                     # line is already defined
  1074                     y_range = max(1.0, max_value - min_value)
       
  1075                 else:
       
  1076                     y_center = 0.5
       
  1077                     y_range = 1.0
       
  1078                 x_min, x_max = start_tick, end_tick
       
  1079                 y_min, y_max = y_center - y_range * 0.55, y_center + y_range * 0.55
       
  1080                 
       
  1081                 if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick:
       
  1082                     if self.VLine is None:
  1166                     if self.VLine is None:
  1083                         self.VLine = self.Axes.axvline(self.CursorTick, color=CURSOR_COLOR)
  1167                         self.VLine = self.Axes.axvline(self.CursorTick, 
       
  1168                                                        color=CURSOR_COLOR)
       
  1169                     
       
  1170                     # Set value of vertical line if already defined
  1084                     else:
  1171                     else:
  1085                         self.VLine.set_xdata((self.CursorTick, self.CursorTick))
  1172                         self.VLine.set_xdata((self.CursorTick, self.CursorTick))
  1086                     self.VLine.set_visible(True)
  1173                     self.VLine.set_visible(True)
  1087                 else:
  1174                 
  1088                     if self.VLine is not None:
  1175                 # Hide vertical line if cursor tick is not defined or reset
  1089                         self.VLine.set_visible(False)
  1176                 elif self.VLine is not None:
       
  1177                     self.VLine.set_visible(False)
       
  1178             
       
  1179             # Graph is orthogonal
  1090             else:
  1180             else:
  1091                 min_start_tick = max(start_tick, self.GetItemsMinCommonTick())
  1181                 # Update tick range, removing ticks that don't have a value for
  1092                 start_tick = max(start_tick, min_start_tick)
  1182                 # each variable
  1093                 end_tick = max(end_tick, min_start_tick)
  1183                 start_tick = max(start_tick, self.GetItemsMinCommonTick())
       
  1184                 end_tick = max(end_tick, start_tick)
  1094                 items = self.ItemsDict.values()
  1185                 items = self.ItemsDict.values()
  1095                 x_data, x_min, x_max = items[0].OrthogonalDataAndRange(start_tick, end_tick)
  1186                 
  1096                 y_data, y_min, y_max = items[1].OrthogonalDataAndRange(start_tick, end_tick)
  1187                 # Get data and range for first variable (X coordinate)
       
  1188                 x_data, x_min, x_max = items[0].GetDataAndValueRange(
       
  1189                                         start_tick, end_tick, not self.ZoomFit)
       
  1190                 # Get data and range for second variable (Y coordinate)
       
  1191                 y_data, y_min, y_max = items[1].GetDataAndValueRange(
       
  1192                                         start_tick, end_tick, not self.ZoomFit)
       
  1193                 
       
  1194                 # Normalize X and Y coordinates value range
       
  1195                 x_min, x_max = merge_ranges([(x_min, x_max)])
       
  1196                 y_min, y_max = merge_ranges([(y_min, y_max)])
       
  1197                 
       
  1198                 # Get X and Y coordinates for cursor if cursor tick is defined 
  1097                 if self.CursorTick is not None:
  1199                 if self.CursorTick is not None:
  1098                     x_cursor, x_forced = items[0].GetValue(self.CursorTick, raw=True)
  1200                     x_cursor, x_forced = items[0].GetValue(
  1099                     y_cursor, y_forced = items[1].GetValue(self.CursorTick, raw=True)
  1201                                             self.CursorTick, raw=True)
  1100                 length = 0
  1202                     y_cursor, y_forced = items[1].GetValue(
  1101                 if x_data is not None and y_data is not None:  
  1203                                             self.CursorTick, raw=True)
  1102                     length = min(len(x_data), len(y_data))
  1204                 
       
  1205                 # Get common data length so that each value has an x and y
       
  1206                 # coordinate
       
  1207                 length = (min(len(x_data), len(y_data))
       
  1208                           if x_data is not None and y_data is not None
       
  1209                           else 0)
       
  1210                 
       
  1211                 # Graph is orthogonal 2D 
  1103                 if len(self.Items) < 3:
  1212                 if len(self.Items) < 3:
       
  1213                     
       
  1214                     # Check that x and y data are not empty
  1104                     if x_data is not None and y_data is not None:
  1215                     if x_data is not None and y_data is not None:
       
  1216                         
       
  1217                         # Add plot to canvas if not yet created
  1105                         if len(self.Plots) == 0:
  1218                         if len(self.Plots) == 0:
  1106                             self.Plots.append(
  1219                             self.Plots.append(
  1107                                 self.Axes.plot(x_data[:, 1][:length], 
  1220                                 self.Axes.plot(x_data[:, 1][:length], 
  1108                                                y_data[:, 1][:length])[0])
  1221                                                y_data[:, 1][:length])[0])
       
  1222                         
       
  1223                         # Set data to already created plot in canvas
  1109                         else:
  1224                         else:
  1110                             self.Plots[0].set_data(
  1225                             self.Plots[0].set_data(
  1111                                 x_data[:, 1][:length], 
  1226                                 x_data[:, 1][:length], 
  1112                                 y_data[:, 1][:length])
  1227                                 y_data[:, 1][:length])
  1113                     
  1228                     
  1114                     if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick:
  1229                     # Display cursor in canvas if a cursor tick is defined and it is
       
  1230                     # include in values tick range
       
  1231                     if (self.CursorTick is not None and 
       
  1232                         start_tick <= self.CursorTick <= end_tick):
       
  1233                         
       
  1234                         # Define a vertical line to display cursor x coordinate
       
  1235                         # if no line is already defined
  1115                         if self.VLine is None:
  1236                         if self.VLine is None:
  1116                             self.VLine = self.Axes.axvline(x_cursor, color=CURSOR_COLOR)
  1237                             self.VLine = self.Axes.axvline(x_cursor, 
       
  1238                                                            color=CURSOR_COLOR)
       
  1239                         # Set value of vertical line if already defined
  1117                         else:
  1240                         else:
  1118                             self.VLine.set_xdata((x_cursor, x_cursor))
  1241                             self.VLine.set_xdata((x_cursor, x_cursor))
       
  1242                         
       
  1243                         
       
  1244                         # Define a horizontal line to display cursor y
       
  1245                         # coordinate if no line is already defined
  1119                         if self.HLine is None:
  1246                         if self.HLine is None:
  1120                             self.HLine = self.Axes.axhline(y_cursor, color=CURSOR_COLOR)
  1247                             self.HLine = self.Axes.axhline(y_cursor, 
       
  1248                                                            color=CURSOR_COLOR)
       
  1249                         # Set value of horizontal line if already defined
  1121                         else:
  1250                         else:
  1122                             self.HLine.set_ydata((y_cursor, y_cursor))
  1251                             self.HLine.set_ydata((y_cursor, y_cursor))
       
  1252                         
  1123                         self.VLine.set_visible(True)
  1253                         self.VLine.set_visible(True)
  1124                         self.HLine.set_visible(True)
  1254                         self.HLine.set_visible(True)
       
  1255                     
       
  1256                     # Hide vertical and horizontal line if cursor tick is not
       
  1257                     # defined or reset
  1125                     else:
  1258                     else:
  1126                         if self.VLine is not None:
  1259                         if self.VLine is not None:
  1127                             self.VLine.set_visible(False)
  1260                             self.VLine.set_visible(False)
  1128                         if self.HLine is not None:
  1261                         if self.HLine is not None:
  1129                             self.HLine.set_visible(False)
  1262                             self.HLine.set_visible(False)
       
  1263                 
       
  1264                 # Graph is orthogonal 3D
  1130                 else:
  1265                 else:
       
  1266                     # Remove all plots already defined in 3D canvas
  1131                     while len(self.Axes.lines) > 0:
  1267                     while len(self.Axes.lines) > 0:
  1132                         self.Axes.lines.pop()
  1268                         self.Axes.lines.pop()
  1133                     z_data, z_min, z_max = items[2].OrthogonalDataAndRange(start_tick, end_tick)
  1269                     
  1134                     if self.CursorTick is not None:
  1270                     # Get data and range for third variable (Z coordinate)
  1135                         z_cursor, z_forced = items[2].GetValue(self.CursorTick, raw=True)
  1271                     z_data, z_min, z_max = items[2].GetDataAndValueRange(
  1136                     if x_data is not None and y_data is not None and z_data is not None:
  1272                                     start_tick, end_tick, not self.ZoomFit)
       
  1273                     
       
  1274                     # Normalize Z coordinate value range
       
  1275                     z_min, z_max = merge_ranges([(z_min, z_max)])
       
  1276                     
       
  1277                     # Check that x, y and z data are not empty
       
  1278                     if (x_data is not None and y_data is not None and 
       
  1279                         z_data is not None):
       
  1280                         
       
  1281                         # Get common data length so that each value has an x, y
       
  1282                         # and z coordinate
  1137                         length = min(length, len(z_data))
  1283                         length = min(length, len(z_data))
       
  1284                         
       
  1285                         # Add plot to canvas
  1138                         self.Axes.plot(x_data[:, 1][:length],
  1286                         self.Axes.plot(x_data[:, 1][:length],
  1139                                        y_data[:, 1][:length],
  1287                                        y_data[:, 1][:length],
  1140                                        zs = z_data[:, 1][:length])
  1288                                        zs = z_data[:, 1][:length])
  1141                     self.Axes.set_zlim(z_min, z_max)
  1289                     
  1142                     if self.CursorTick is not None and start_tick <= self.CursorTick <= end_tick:
  1290                     # Display cursor in canvas if a cursor tick is defined and
       
  1291                     # it is include in values tick range
       
  1292                     if (self.CursorTick is not None and 
       
  1293                         start_tick <= self.CursorTick <= end_tick):
       
  1294                         
       
  1295                         # Get Z coordinate for cursor
       
  1296                         z_cursor, z_forced = items[2].GetValue(
       
  1297                                                 self.CursorTick, raw=True)
       
  1298                         
       
  1299                         # Add 3 lines parallel to x, y and z axis to display
       
  1300                         # cursor position in 3D
  1143                         for kwargs in [{"xs": numpy.array([x_min, x_max])},
  1301                         for kwargs in [{"xs": numpy.array([x_min, x_max])},
  1144                                        {"ys": numpy.array([y_min, y_max])},
  1302                                        {"ys": numpy.array([y_min, y_max])},
  1145                                        {"zs": numpy.array([z_min, z_max])}]:
  1303                                        {"zs": numpy.array([z_min, z_max])}]:
  1146                             for param, value in [("xs", numpy.array([x_cursor, x_cursor])),
  1304                             for param, value in [
  1147                                                  ("ys", numpy.array([y_cursor, y_cursor])),
  1305                                     ("xs", numpy.array([x_cursor, x_cursor])),
  1148                                                  ("zs", numpy.array([z_cursor, z_cursor]))]:
  1306                                     ("ys", numpy.array([y_cursor, y_cursor])),
       
  1307                                     ("zs", numpy.array([z_cursor, z_cursor]))]:
  1149                                 kwargs.setdefault(param, value)
  1308                                 kwargs.setdefault(param, value)
  1150                             kwargs["color"] = CURSOR_COLOR
  1309                             kwargs["color"] = CURSOR_COLOR
  1151                             self.Axes.plot(**kwargs)
  1310                             self.Axes.plot(**kwargs)
  1152                 
  1311                     
       
  1312                     # Set Z axis limits
       
  1313                     self.Axes.set_zlim(z_min, z_max)
       
  1314             
       
  1315             # Set X and Y axis limits
  1153             self.Axes.set_xlim(x_min, x_max)
  1316             self.Axes.set_xlim(x_min, x_max)
  1154             self.Axes.set_ylim(y_min, y_max)
  1317             self.Axes.set_ylim(y_min, y_max)
  1155         
  1318         
  1156         variable_name_mask = self.ParentWindow.GetVariableNameMask()
  1319         # Get value and forced flag for each variable displayed in graph
  1157         if self.CursorTick is not None:
  1320         # If cursor tick is not defined get value and flag of last received
  1158             values, forced = apply(zip, [item.GetValue(self.CursorTick) for item in self.Items])
  1321         # or get value and flag of variable at cursor tick
  1159         else:
  1322         values, forced = apply(zip, [
  1160             values, forced = apply(zip, [(item.GetValue(), item.IsForced()) for item in self.Items])
  1323                 (item.GetValue(self.CursorTick)
  1161         labels = [item.GetVariable(variable_name_mask) for item in self.Items]
  1324                  if self.CursorTick is not None
       
  1325                  else (item.GetValue(), item.IsForced()))
       
  1326                 for item in self.Items])
       
  1327         
       
  1328         # Get path of each variable displayed simplified using panel variable
       
  1329         # name mask
       
  1330         labels = [item.GetVariable(self.ParentWindow.GetVariableNameMask()) 
       
  1331                   for item in self.Items]
       
  1332         
       
  1333         # Get style for each variable according to 
  1162         styles = map(lambda x: {True: 'italic', False: 'normal'}[x], forced)
  1334         styles = map(lambda x: {True: 'italic', False: 'normal'}[x], forced)
       
  1335         
       
  1336         # Graph is orthogonal 3D, set variables path as 3D axis label
  1163         if self.Is3DCanvas():
  1337         if self.Is3DCanvas():
  1164             for idx, label_func in enumerate([self.Axes.set_xlabel, 
  1338             for idx, label_func in enumerate([self.Axes.set_xlabel, 
  1165                                               self.Axes.set_ylabel,
  1339                                               self.Axes.set_ylabel,
  1166                                               self.Axes.set_zlabel]):
  1340                                               self.Axes.set_zlabel]):
  1167                 label_func(labels[idx], fontdict={'size': 'small','color': COLOR_CYCLE[idx]})
  1341                 label_func(labels[idx], fontdict={'size': 'small',
       
  1342                                                   'color': COLOR_CYCLE[idx]})
       
  1343         
       
  1344         # Graph is not orthogonal 3D, set variables path in axes labels
  1168         else:
  1345         else:
  1169             for label, text in zip(self.AxesLabels, labels):
  1346             for label, text in zip(self.AxesLabels, labels):
  1170                 label.set_text(text)
  1347                 label.set_text(text)
       
  1348         
       
  1349         # Set value label text and style according to value and forced flag for
       
  1350         # each variable displayed
  1171         for label, value, style in zip(self.Labels, values, styles):
  1351         for label, value, style in zip(self.Labels, values, styles):
  1172             label.set_text(value)
  1352             label.set_text(value)
  1173             label.set_style(style)
  1353             label.set_style(style)
  1174         
  1354         
       
  1355         # Refresh figure
  1175         self.draw()
  1356         self.draw()
  1176 
  1357 
  1177     def draw(self, drawDC=None):
  1358     def draw(self, drawDC=None):
  1178         """
  1359         """
  1179         Render the figure.
  1360         Render the figure.