372 setattr(self.VariablesGrid, "_AddRow", _AddVariable) |
372 setattr(self.VariablesGrid, "_AddRow", _AddVariable) |
373 |
373 |
374 def _DeleteVariable(row): |
374 def _DeleteVariable(row): |
375 item = self.Table.GetItem(row) |
375 item = self.Table.GetItem(row) |
376 self.RemoveDataConsumer(item) |
376 self.RemoveDataConsumer(item) |
|
377 for infos in self.GraphicsAxes: |
|
378 if item in infos["items"]: |
|
379 if len(infos["items"]) == 1: |
|
380 self.GraphicsAxes.remove(infos) |
|
381 else: |
|
382 infos["items"].remove(item) |
|
383 break |
377 self.Table.RemoveItem(row) |
384 self.Table.RemoveItem(row) |
378 self.ResetGraphics() |
385 self.ResetGraphics() |
379 self.RefreshGrid() |
386 self.RefreshGrid() |
380 setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) |
387 setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable) |
381 |
388 |
403 self.VariablesGrid.RefreshButtons() |
410 self.VariablesGrid.RefreshButtons() |
404 |
411 |
405 if USE_MPL: |
412 if USE_MPL: |
406 self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) |
413 self.GraphicsPanel = wx.Panel(self, style=wx.TAB_TRAVERSAL) |
407 |
414 |
408 graphics_panel_sizer = wx.BoxSizer(wx.VERTICAL) |
415 self.GraphicsPanelSizer = wx.BoxSizer(wx.VERTICAL) |
409 |
416 |
410 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
417 graphics_button_sizer = wx.BoxSizer(wx.HORIZONTAL) |
411 graphics_panel_sizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) |
418 self.GraphicsPanelSizer.AddSizer(graphics_button_sizer, border=5, flag=wx.GROW|wx.ALL) |
412 |
419 |
413 range_label = wx.StaticText(self.GraphicsPanel, label=_('Range:')) |
420 range_label = wx.StaticText(self.GraphicsPanel, label=_('Range:')) |
414 graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) |
421 graphics_button_sizer.AddWindow(range_label, flag=wx.ALIGN_CENTER_VERTICAL) |
415 |
422 |
416 self.CanvasRange = wx.ComboBox(self.GraphicsPanel, style=wx.CB_READONLY) |
423 self.CanvasRange = wx.ComboBox(self.GraphicsPanel, style=wx.CB_READONLY) |
440 self.OnPositionChanging, self.CanvasPosition) |
447 self.OnPositionChanging, self.CanvasPosition) |
441 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, |
448 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEUP, |
442 self.OnPositionChanging, self.CanvasPosition) |
449 self.OnPositionChanging, self.CanvasPosition) |
443 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
450 self.CanvasPosition.Bind(wx.EVT_SCROLL_PAGEDOWN, |
444 self.OnPositionChanging, self.CanvasPosition) |
451 self.OnPositionChanging, self.CanvasPosition) |
445 graphics_panel_sizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) |
452 self.GraphicsPanelSizer.AddWindow(self.CanvasPosition, border=5, flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM) |
446 |
453 |
447 self.GraphicsCanvasWindow = wx.ScrolledWindow(self.GraphicsPanel, style=wx.HSCROLL|wx.VSCROLL) |
454 self.GraphicsCanvasWindow = wx.ScrolledWindow(self.GraphicsPanel, style=wx.HSCROLL|wx.VSCROLL) |
448 self.GraphicsCanvasWindow.Bind(wx.EVT_SIZE, self.OnGraphicsCanvasWindowResize) |
455 self.GraphicsCanvasWindow.Bind(wx.EVT_SIZE, self.OnGraphicsCanvasWindowResize) |
449 graphics_panel_sizer.AddWindow(self.GraphicsCanvasWindow, 1, flag=wx.GROW) |
456 self.GraphicsPanelSizer.AddWindow(self.GraphicsCanvasWindow, 1, flag=wx.GROW) |
450 |
457 |
451 graphics_canvas_window_sizer = wx.BoxSizer(wx.VERTICAL) |
458 graphics_canvas_window_sizer = wx.BoxSizer(wx.VERTICAL) |
452 |
459 |
453 self.GraphicsFigure = matplotlib.figure.Figure() |
460 self.GraphicsFigure = matplotlib.figure.Figure() |
454 self.GraphicsFigure.subplots_adjust(hspace=0) |
461 self.GraphicsFigure.subplots_adjust(hspace=0) |
467 self.Graphics3DAxes.set_color_cycle(['b']) |
474 self.Graphics3DAxes.set_color_cycle(['b']) |
468 setattr(self.Graphics3DAxes, "_on_move", self.OnGraphics3DMotion) |
475 setattr(self.Graphics3DAxes, "_on_move", self.OnGraphics3DMotion) |
469 |
476 |
470 self.Graphics3DCanvas = FigureCanvas(self.GraphicsPanel, -1, self.Graphics3DFigure) |
477 self.Graphics3DCanvas = FigureCanvas(self.GraphicsPanel, -1, self.Graphics3DFigure) |
471 self.Graphics3DCanvas.SetMinSize(wx.Size(1, 1)) |
478 self.Graphics3DCanvas.SetMinSize(wx.Size(1, 1)) |
472 graphics_panel_sizer.AddWindow(self.Graphics3DCanvas, 1, flag=wx.GROW) |
479 self.GraphicsPanelSizer.AddWindow(self.Graphics3DCanvas, 1, flag=wx.GROW) |
473 |
480 |
474 self.Graphics3DAxes.mouse_init() |
481 self.Graphics3DAxes.mouse_init() |
475 |
482 |
476 self.GraphicsPanel.SetSizer(graphics_panel_sizer) |
483 self.GraphicsPanel.SetSizer(self.GraphicsPanelSizer) |
477 |
484 |
478 self.SplitHorizontally(self.MainPanel, self.GraphicsPanel, -200) |
485 self.SplitHorizontally(self.MainPanel, self.GraphicsPanel, -200) |
479 |
486 |
480 else: |
487 else: |
481 self.Initialize(self.MainPanel) |
488 self.Initialize(self.MainPanel) |
523 |
530 |
524 if USE_MPL and (not self.Fixed or self.Force): |
531 if USE_MPL and (not self.Fixed or self.Force): |
525 self.Force = False |
532 self.Force = False |
526 |
533 |
527 # Refresh graphics |
534 # Refresh graphics |
528 idx = 0 |
|
529 start_tick, end_tick = self.StartTick, self.StartTick + self.CurrentRange |
535 start_tick, end_tick = self.StartTick, self.StartTick + self.CurrentRange |
530 for item in self.Table.GetData(): |
536 for infos in self.GraphicsAxes: |
531 data = item.GetData(start_tick, end_tick) |
537 min_value = max_value = None |
532 if data is not None: |
538 |
533 min_value, max_value = item.GetRange() |
539 for idx, item in enumerate(infos["items"]): |
534 if min_value is not None and max_value is not None: |
540 data = item.GetData(start_tick, end_tick) |
535 y_center = (min_value + max_value) / 2. |
541 if data is not None: |
536 y_range = max(1.0, max_value - min_value) |
542 item_min_value, item_max_value = item.GetRange() |
537 else: |
543 if min_value is None: |
538 y_center = 0.5 |
544 min_value = item_min_value |
539 y_range = 1.0 |
545 elif item_min_value is not None: |
540 self.GraphicsAxes[idx].clear() |
546 min_value = min(min_value, item_min_value) |
541 self.GraphicsAxes[idx].plot(data[:, 0], data[:, 1]) |
547 if max_value is None: |
542 self.GraphicsAxes[idx].set_xlim(start_tick, end_tick) |
548 max_value = item_max_value |
543 self.GraphicsAxes[idx].set_ylim( |
549 elif item_max_value is not None: |
544 y_center - y_range * 0.55, y_center + y_range * 0.55) |
550 max_value = max(max_value, item_max_value) |
545 idx += 1 |
551 |
546 if idx > 0: |
552 if len(infos["plots"]) <= idx: |
|
553 infos["plots"].append(infos["axes"].plot(data[:, 0], data[:, 1])[0]) |
|
554 else: |
|
555 infos["plots"][idx].set_data(data[:, 0], data[:, 1]) |
|
556 |
|
557 if min_value is not None and max_value is not None: |
|
558 y_center = (min_value + max_value) / 2. |
|
559 y_range = max(1.0, max_value - min_value) |
|
560 else: |
|
561 y_center = 0.5 |
|
562 y_range = 1.0 |
|
563 infos["axes"].set_xlim(start_tick, end_tick) |
|
564 infos["axes"].set_ylim(y_center - y_range * 0.55, y_center + y_range * 0.55) |
|
565 |
|
566 if len(self.GraphicsAxes) > 0: |
547 self.GraphicsCanvas.draw() |
567 self.GraphicsCanvas.draw() |
548 |
568 |
549 # Refresh 3D graphics |
569 # Refresh 3D graphics |
550 while len(self.Graphics3DAxes.lines) > 0: |
570 while len(self.Graphics3DAxes.lines) > 0: |
551 self.Graphics3DAxes.lines.pop() |
571 self.Graphics3DAxes.lines.pop() |
748 return |
768 return |
749 item = VariableTableItem(self, iec_path) |
769 item = VariableTableItem(self, iec_path) |
750 result = self.AddDataConsumer(iec_path.upper(), item) |
770 result = self.AddDataConsumer(iec_path.upper(), item) |
751 if result is not None or force: |
771 if result is not None or force: |
752 self.Table.InsertItem(idx, item) |
772 self.Table.InsertItem(idx, item) |
|
773 if item.IsNumVariable(): |
|
774 self.GraphicsAxes.append({ |
|
775 "items": [item], |
|
776 "axes": None, |
|
777 "type": "y", |
|
778 "plots": []}) |
753 item.SetAxis3D(int(axis3D)) |
779 item.SetAxis3D(int(axis3D)) |
754 self.ResetGraphics() |
780 self.ResetGraphics() |
755 self.RefreshGrid() |
781 self.RefreshGrid() |
756 |
782 |
757 def GetDebugVariables(self): |
783 def GetDebugVariables(self): |
767 item.ResetData() |
793 item.ResetData() |
768 |
794 |
769 def ResetGraphics(self): |
795 def ResetGraphics(self): |
770 if USE_MPL: |
796 if USE_MPL: |
771 self.GraphicsFigure.clear() |
797 self.GraphicsFigure.clear() |
772 self.GraphicsAxes = [] |
798 |
773 |
799 axes_num = len(self.GraphicsAxes) |
774 axes_num = 0 |
|
775 for item in self.Table.GetData(): |
|
776 if item.IsNumVariable(): |
|
777 axes_num += 1 |
|
778 |
|
779 for idx in xrange(axes_num): |
800 for idx in xrange(axes_num): |
780 if idx == 0: |
801 if idx == 0: |
781 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1) |
802 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1) |
782 else: |
803 else: |
783 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1, sharex=self.GraphicsAxes[0]) |
804 axes = self.GraphicsFigure.add_subplot(axes_num, 1, idx + 1, sharex=self.GraphicsAxes[0]["axes"]) |
784 self.GraphicsAxes.append(axes) |
805 self.GraphicsAxes[idx]["axes"] = axes |
|
806 self.GraphicsAxes[idx]["plots"] = [] |
785 |
807 |
786 self.RefreshGraphicsCanvasWindowScrollbars() |
808 self.RefreshGraphicsCanvasWindowScrollbars() |
787 self.GraphicsCanvas.draw() |
809 self.GraphicsCanvas.draw() |
788 |
810 |
789 self.Reset3DGraphics() |
811 self.Reset3DGraphics() |
798 max_tick = max(xaxis[0, 0], yaxis[0, 0], zaxis[0, 0]) |
820 max_tick = max(xaxis[0, 0], yaxis[0, 0], zaxis[0, 0]) |
799 if max_tick is not None: |
821 if max_tick is not None: |
800 self.Axis3DValues = (axis, max_tick) |
822 self.Axis3DValues = (axis, max_tick) |
801 else: |
823 else: |
802 self.Axis3DValues = (axis, 0) |
824 self.Axis3DValues = (axis, 0) |
|
825 self.Graphics3DCanvas.Show() |
|
826 else: |
|
827 self.Graphics3DCanvas.Hide() |
|
828 self.GraphicsPanelSizer.Layout() |
803 |
829 |
804 def OnGraphics3DMotion(self, event): |
830 def OnGraphics3DMotion(self, event): |
805 current_time = gettime() |
831 current_time = gettime() |
806 if current_time - self.LastMotionTime > REFRESH_PERIOD: |
832 if current_time - self.LastMotionTime > REFRESH_PERIOD: |
807 self.LastMotionTime = current_time |
833 self.LastMotionTime = current_time |