Source code for pyfmi.common.plotting.plot_gui

#!/usr/bin/env python 
# -*- coding: utf-8 -*-

# Copyright (C) 2010 Modelon AB
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, version 3 of the License.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.


import matplotlib
matplotlib.interactive(True)
matplotlib.use('WXAgg')

from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
from matplotlib.figure import Figure
from matplotlib import rcParams
import fnmatch
import re

#GUI modules
try:
    import wx
    import wx.lib.agw.customtreectrl as wxCustom
    import wx.lib.agw.aui as aui
except ImportError:
    print("WX-Python not found. The GUI will not work.")

#JModelica related imports
try:
    from pyfmi.common.io import ResultDymolaTextual
    from pyfmi.common.io import ResultDymolaBinary
    from pyfmi.common.io import ResultCSVTextual
    from pyfmi.common.io import JIOError
except ImportError:
    try:
        from pyjmi.common.io import ResultDymolaTextual
        from pyjmi.common.io import ResultDymolaBinary
        from pyjmi.common.io import ResultCSVTextual
        from pyjmi.common.io import JIOError
    except ImportError:
        print("JModelica Python package was not found.")

#Import general modules
import os as O

ID_GRID    = 15001
ID_LICENSE = 15002
ID_LABELS  = 15003
ID_AXIS    = 15004
ID_MOVE    = 15005
ID_ZOOM    = 15006
ID_RESIZE  = 15007
ID_LINES   = 15008
ID_CLEAR   = 15009

[docs]def convert_filter(expression): """ Convert a filter based on unix filename pattern matching to a list of regular expressions. """ regexp = [] if isinstance(expression,str): regex = fnmatch.translate(expression) regexp = [re.compile(regex)] elif isinstance(expression,list): for i in expression: regex = fnmatch.translate(i) regexp.append(re.compile(regex)) else: raise Exception("Unknown input.") return regexp
[docs]def match(name, filter_list): found = False for j in range(len(filter_list)): if re.match(filter_list[j], name): found = True break return found
[docs]class MainGUI(wx.Frame): sizeHeightDefault=900 sizeLengthDefault=675 sizeHeightMin=100 sizeLengthMin=130 sizeTreeMin=200 sizeTreeDefault=sizeTreeMin+40 def __init__(self, parent, ID, filename=None): self.title = "JModelica.org Plot GUI" wx.Frame.__init__(self, parent, ID, self.title, wx.DefaultPosition, wx.Size(self.sizeHeightDefault, self.sizeLengthDefault)) #Handle idle events #wx.IdleEvent.SetMode(wx.IDLE_PROCESS_SPECIFIED) #Variables for the results self.ResultFiles = [] #Contains all the result files self.PlotVariables = [[]] #Contains all the variables for the different plots self.ResultIndex = 0 #Index of the result file self.PlotIndex = 0 #Index of the plot variables connected to the different plots #Settings variables self.grid = True self.zoom = True self.move = False #Create menus and status bars self.CreateStatusBar() #Create a statusbar at the bottom self.CreateMenu() #Create the normal menu #Create the main window self.verticalSplitter = wx.SplitterWindow(self, -1, style = wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D) #Create the positioners self.leftPanel = wx.Panel(self.verticalSplitter) self.leftSizer = wx.BoxSizer(wx.VERTICAL) self.rightPanel = wx.Panel(self.verticalSplitter) self.rightSizer = wx.BoxSizer(wx.VERTICAL) #Create the panels (Tree and Plot) if wx.VERSION < (2,8,11,0): self.noteBook = aui.AuiNotebook(self.rightPanel, style= aui.AUI_NB_TOP | aui.AUI_NB_TAB_SPLIT | aui.AUI_NB_TAB_MOVE | aui.AUI_NB_SCROLL_BUTTONS | aui.AUI_NB_CLOSE_ON_ACTIVE_TAB | aui.AUI_NB_DRAW_DND_TAB) self.tree = VariableTree(self.noteBook, self.leftPanel,style = wx.SUNKEN_BORDER | wxCustom.TR_HAS_BUTTONS | wxCustom.TR_HAS_VARIABLE_ROW_HEIGHT | wxCustom.TR_HIDE_ROOT | wxCustom.TR_ALIGN_WINDOWS) else: self.noteBook = aui.AuiNotebook(self.rightPanel, agwStyle= aui.AUI_NB_TOP | aui.AUI_NB_TAB_SPLIT | aui.AUI_NB_TAB_MOVE | aui.AUI_NB_SCROLL_BUTTONS | aui.AUI_NB_CLOSE_ON_ACTIVE_TAB | aui.AUI_NB_DRAW_DND_TAB) self.tree = VariableTree(self.noteBook, self.leftPanel,style = wx.SUNKEN_BORDER, agwStyle = wxCustom.TR_HAS_BUTTONS | wxCustom.TR_HAS_VARIABLE_ROW_HEIGHT | wxCustom.TR_HIDE_ROOT | wxCustom.TR_ALIGN_WINDOWS) self.plotPanels = [PlotPanel(self.noteBook,self.grid, move=self.move, zoom=self.zoom)] self.noteBook.AddPage(self.plotPanels[0],"Plot 1") self.filterPanel = FilterPanel(self, self.leftPanel, self.tree) #Add the panels to the positioners self.leftSizer.Add(self.tree,1,wx.EXPAND) self.leftSizer.Add(self.filterPanel,0,wx.EXPAND) self.rightSizer.Add(self.noteBook,1,wx.EXPAND) self.verticalSplitter.SplitVertically(self.leftPanel, self.rightPanel,self.sizeTreeDefault) #self.verticalSplitter.SetMinimumPaneSize(self.sizeTreeMin) self.verticalSplitter.SetMinimumPaneSize(self.filterPanel.GetBestSize()[0]) #Position the main windows self.leftPanel.SetSizer(self.leftSizer) self.rightPanel.SetSizer(self.rightSizer) self.mainSizer = wx.BoxSizer() #Create the main positioner self.mainSizer.Add(self.verticalSplitter, 1, wx.EXPAND) #Add the vertical splitter self.SetSizer(self.mainSizer) #Set the positioner to the main window self.SetMinSize((self.sizeHeightMin,self.sizeLengthMin)) #Set minimum sizes #Bind the exit event from the "cross" self.Bind(wx.EVT_CLOSE, self.OnMenuExit) #Bind the tree item checked event self.tree.Bind(wxCustom.EVT_TREE_ITEM_CHECKED, self.OnTreeItemChecked) #Bind the key press event self.tree.Bind(wx.EVT_KEY_DOWN, self.OnKeyPress) #Bind the closing of a tab self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnCloseTab, self.noteBook) #Bind the changing of a tab self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CHANGING, self.OnTabChanging, self.noteBook) #Bind the changed of a tab self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabChanged, self.noteBook) if not filename == None: self._OpenFile(filename) self.Centre(True) #Position the GUI in the centre of the screen self.Show(True) #Show the Plot GUI
[docs] def CreateMenu(self): #Creating the menu filemenu = wx.Menu() helpmenu = wx.Menu() editmenu = wx.Menu() viewmenu = wx.Menu() menuBar = wx.MenuBar() #Create the menu options # Main self.menuOpen = filemenu.Append(wx.ID_OPEN, "&Open\tCtrl+O","Open a result.") self.menuSaveFig = filemenu.Append(wx.ID_SAVE, "&Save\tCtrl+S", "Save the current figure.") filemenu.AppendSeparator() #Append a seperator between Open and Exit self.menuExit = filemenu.Append(wx.ID_EXIT,"E&xit\tCtrl+X"," Terminate the program.") # Edit self.editAdd = editmenu.Append(wx.ID_ADD,"A&dd Plot","Add a plot window.") self.editClear = editmenu.Append(wx.ID_CLEAR, "Clear Plot", "Clear the current plot window.") editmenu.AppendSeparator() self.editAxisLabels = editmenu.Append(ID_AXIS,"Axis / Labels", "Edit the axis and labels of the current plot.") self.editLinesLegends = editmenu.Append(ID_LINES, "Lines / Legends", "Edit the lines and the legend of the current plot.") # View self.viewGrid = viewmenu.Append(ID_GRID,"&Grid","Show/Hide Grid.",kind=wx.ITEM_CHECK) viewmenu.AppendSeparator() #Append a seperator self.viewMove = viewmenu.Append(ID_MOVE,"Move","Use the mouse to move the plot.",kind=wx.ITEM_RADIO) self.viewZoom = viewmenu.Append(ID_ZOOM,"Zoom","Use the mouse for zooming.",kind=wx.ITEM_RADIO) viewmenu.AppendSeparator() self.viewResize = viewmenu.Append(ID_RESIZE, "Resize", "Resize the current plot.") #Check items viewmenu.Check(ID_GRID, self.grid) viewmenu.Check(ID_ZOOM, self.zoom) viewmenu.Check(ID_MOVE, self.move) # Help self.helpLicense = helpmenu.Append(ID_LICENSE, "License","Show the license.") self.helpAbout = helpmenu.Append(wx.ID_ABOUT, "&About"," Information about this program.") #Setting up the menu menuBar.Append(filemenu,"&File") #Adding the "filemenu" to the MenuBar menuBar.Append(editmenu,"&Edit") #Adding the "editmenu" to the MenuBar menuBar.Append(viewmenu,"&View") #Adding the "viewmenu" to the MenuBar menuBar.Append(helpmenu,"&Help") #Adding the "helpmenu" to the MenuBar #Binding the events self.Bind(wx.EVT_MENU, self.OnMenuOpen, self.menuOpen) self.Bind(wx.EVT_MENU, self.OnMenuSaveFig, self.menuSaveFig) self.Bind(wx.EVT_MENU, self.OnMenuExit, self.menuExit) self.Bind(wx.EVT_MENU, self.OnMenuAdd, self.editAdd) self.Bind(wx.EVT_MENU, self.OnMenuClear, self.editClear) self.Bind(wx.EVT_MENU, self.OnMenuAxisLabels, self.editAxisLabels) self.Bind(wx.EVT_MENU, self.OnMenuLinesLegends, self.editLinesLegends) self.Bind(wx.EVT_MENU, self.OnMenuResize, self.viewResize) self.Bind(wx.EVT_MENU, self.OnMenuGrid, self.viewGrid) self.Bind(wx.EVT_MENU, self.OnMenuMove, self.viewMove) self.Bind(wx.EVT_MENU, self.OnMenuZoom, self.viewZoom) self.Bind(wx.EVT_MENU, self.OnMenuLicense, self.helpLicense) self.Bind(wx.EVT_MENU, self.OnMenuAbout, self.helpAbout) self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content. #Set keyboard shortcuts hotKeysTable = wx.AcceleratorTable([(wx.ACCEL_CTRL, ord("O"), self.menuOpen.GetId()), (wx.ACCEL_CTRL, ord("S"), self.menuSaveFig.GetId()), (wx.ACCEL_CTRL, ord("X"), self.menuExit.GetId())]) self.SetAcceleratorTable(hotKeysTable) #Disable Lines and Legends self.editLinesLegends.Enable(False)
[docs] def OnMenuMove(self, event): self.move = True self.zoom = False for i in range(self.noteBook.GetPageCount()): self.noteBook.GetPage(i).UpdateSettings(move = self.move, zoom = self.zoom)
[docs] def OnMenuZoom(self, event): self.move = False self.zoom = True for i in range(self.noteBook.GetPageCount()): self.noteBook.GetPage(i).UpdateSettings(move = self.move, zoom = self.zoom)
[docs] def OnMenuExit(self, event): self.Destroy() #Close the GUI
[docs] def OnMenuAbout(self, event): dlg = wx.MessageDialog(self, 'JModelica.org Plot GUI.\n', 'About', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy()
[docs] def OnMenuResize(self, event): IDPlot = self.noteBook.GetSelection() self.noteBook.GetPage(IDPlot).ReSize()
[docs] def OnMenuOpen(self, event): #Open the file window dlg = wx.FileDialog(self, "Open result file(s)", wildcard="Supported files (.txt, .mat, .csv)|*.txt;*.mat;*.csv|Text files (.txt)|*.txt|MATLAB files (.mat)|*.mat|Comma-Separated Values files (.csv)|*.csv|All files (*.*)|*.*", style=wx.FD_MULTIPLE) #If OK load the results if dlg.ShowModal() == wx.ID_OK: for n in dlg.GetFilenames(): self._OpenFile(O.path.join(dlg.GetDirectory(),n)) dlg.Destroy() #Destroy the popup window
[docs] def OnMenuSaveFig(self, event): #Open the file window dlg = wx.FileDialog(self, "Choose a filename to save to",wildcard="Portable Network Graphics (*.png)|*.png|" \ "Encapsulated Postscript (*.eps)|*.eps|" \ "Enhanced Metafile (*.emf)|*.emf|" \ "Portable Document Format (*.pdf)|*.pdf|" \ "Postscript (*.ps)|*.ps|" \ "Raw RGBA bitmap (*.raw *.rgba)|*.raw;*.rgba|" \ "Scalable Vector Graphics (*.svg *.svgz)|*.svg;*.svgz", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT) #If OK save the figure if dlg.ShowModal() == wx.ID_OK: self.SetStatusText("Saving figure...") #Change the statusbar IDPlot = self.noteBook.GetSelection() self.noteBook.GetPage(IDPlot).Save(dlg.GetPath()) self.SetStatusText("") #Change the statusbar dlg.Destroy() #Destroy the popup window
[docs] def OnMenuAdd(self, event): #Add a new list for the plot variables connect to the plot self.PlotVariables.append([]) self.PlotIndex += 1 #Add a new plot panel to the notebook self.plotPanels.append(PlotPanel(self.noteBook,self.grid,move=self.move, zoom=self.zoom)) self.noteBook.AddPage(self.plotPanels[-1],"Plot "+str(self.PlotIndex+1)) #Enable labels and axis options self.editAxisLabels.Enable(True)
[docs] def OnMenuClear(self, event): #Clear the current activated plot window IDPlot = self.noteBook.GetSelection() if IDPlot != -1: plotWindow = self.noteBook.GetPage(IDPlot) #Uncheck all variables for i,var in enumerate(self.noteBook.GetPage(IDPlot).GetPlotVariables()): self.tree.CheckItem2(var[1],checked=False,torefresh=True) #Delete all variables plotWindow.DeleteAllPlotVariables() #Disable Lines and Legends self.editLinesLegends.Enable(False) plotWindow.SetDefaultSettings() plotWindow.UpdateSettings(axes=[0.0,1.0,0.0,1.0]) plotWindow.Draw() plotWindow.UpdateSettings(axes=[None,None,None,None])
[docs] def OnMenuLinesLegends(self, event): IDPlot = self.noteBook.GetSelection() plotWindow = self.noteBook.GetPage(IDPlot) #Create the axis dialog dlg = DialogLinesLegends(self,self.noteBook.GetPage(IDPlot)) #Open the dialog and update options if OK if dlg.ShowModal() == wx.ID_OK: dlg.ApplyChanges() #Apply Changes legend = dlg.GetValues() plotWindow.UpdateSettings(legendposition=legend) plotWindow.Draw() #Destroy the dialog dlg.Destroy()
[docs] def OnMenuAxisLabels(self, event): IDPlot = self.noteBook.GetSelection() plotWindow = self.noteBook.GetPage(IDPlot) #Create the axis dialog dlg = DialogAxisLabels(self,self.noteBook.GetPage(IDPlot)) #Open the dialog and update options if OK if dlg.ShowModal() == wx.ID_OK: xmax,xmin,ymax,ymin,title,xlabel,ylabel,xscale,yscale = dlg.GetValues() try: xmax=float(xmax) except ValueError: xmax=None try: xmin=float(xmin) except ValueError: xmin=None try: ymax=float(ymax) except ValueError: ymax=None try: ymin=float(ymin) except ValueError: ymin=None plotWindow.UpdateSettings(axes=[xmin,xmax,ymin,ymax], title=title,xlabel=xlabel,ylabel=ylabel, xscale=xscale, yscale=yscale) plotWindow.DrawSettings() #Destroy the dialog dlg.Destroy()
[docs] def OnMenuGrid(self, event): self.grid = not self.grid for i in range(self.noteBook.GetPageCount()): self.noteBook.GetPage(i).UpdateSettings(grid = self.grid) self.noteBook.GetPage(i).DrawSettings()
[docs] def OnTreeItemChecked(self, event): self.SetStatusText("Drawing figure...") item = event.GetItem() #ID = self.tree.FindIndexParent(item) ID = -1 #Not used IDPlot = self.noteBook.GetSelection() if IDPlot != -1: #If there exist a plot window data = self.tree.GetPyData(item) #print "Variable: ", data["variable_id"], item #Store plot variables or "unstore" if self.tree.IsItemChecked(item): #Draw #Add to Plot panel self.noteBook.GetPage(IDPlot).AddPlotVariable(ID,item,data) data["item_checked"] = IDPlot else: #Undraw #Remove from panel self.noteBook.GetPage(IDPlot).DeletePlotVariable(data["variable_id"]) data["item_checked"] = None self.noteBook.GetPage(IDPlot).Draw() lines = self.noteBook.GetPage(IDPlot).GetLines() if len(lines) != 0: #Enable Lines and Legends self.editLinesLegends.Enable(True) else: #Disable Lines and Legends self.editLinesLegends.Enable(False) else: #Dont allow an item to be checked if there exist no plot window self.tree.CheckItem2(item,checked=False,torefresh=True) self.SetStatusText("")
[docs] def OnKeyPress(self, event): keycode = event.GetKeyCode() #Get the key pressed #If the key is Delete if keycode == wx.WXK_DELETE: self.SetStatusText("Deleting Result...") ID = self.tree.FindIndexParent(self.tree.GetSelection()) data = self.tree.GetPyData(self.tree.GetSelection()) IDPlot = self.noteBook.GetSelection() if ID >= 0: #If id is less then 0, no item is selected self.ResultFiles.pop(ID) #Delete the result object from the list self.tree.DeleteParent(self.tree.GetSelection()) #Redraw for i in range(self.noteBook.GetPageCount()): self.noteBook.GetPage(i).DeletePlotVariable(global_id=data["result_id"]) self.noteBook.GetPage(i).Draw() self.SetStatusText("")
[docs] def OnCloseTab(self, event): self.OnTabChanging(event) self.PlotVariables.pop(event.GetSelection()) #Delete the plot self.plotPanels.pop(event.GetSelection()) #MAYBE! #variables associated with the current plot #Disable changing of labels and axis if there is no Plot if self.noteBook.GetPageCount() == 1: self.editAxisLabels.Enable(False) self.editLinesLegends.Enable(False)
[docs] def OnTabChanging(self, event): #print "Changing: ", self.noteBook.GetSelection() self.UpdateCheckedItemTree(check=False)
[docs] def OnTabChanged(self,event): #print "Changed: ", self.noteBook.GetSelection() self.UpdateCheckedItemTree(check=True)
[docs] def UpdateCheckedItemTree(self, check=True): #print "Update: ", self.noteBook.GetSelection() IDPlot = self.noteBook.GetSelection() #Check the items related to the previous plot if IDPlot != -1: for i,var in enumerate(self.noteBook.GetPage(IDPlot).GetPlotVariables()): self.tree.CheckItem2(var[1],checked=check,torefresh=True) lines = self.noteBook.GetPage(IDPlot).GetLines() if len(lines) != 0: #Enable Lines and Legends self.editLinesLegends.Enable(True) else: #Disable Lines and Legends self.editLinesLegends.Enable(False)
[docs] def OnMenuLicense(self, event): desc = "Copyright (C) 2011 Modelon AB\n\n"\ "This program is free software: you can redistribute it and/or modify "\ "it under the terms of the GNU General Public License as published by "\ "the Free Software Foundation, version 3 of the License.\n\n"\ "This program is distributed in the hope that it will be useful, "\ "but WITHOUT ANY WARRANTY; without even the implied warranty of "\ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "\ "GNU General Public License for more details.\n\n"\ "You should have received a copy of the GNU General Public License "\ "along with this program. If not, see <http://www.gnu.org/licenses/>. " dlg = wx.MessageDialog(self, desc, 'License', wx.OK | wx.ICON_INFORMATION) dlg.ShowModal() dlg.Destroy()
def _OpenFile(self,filename): # Extract filename and result name n = str(filename) if n.find('\\') > n.find('/'): res_name = n.split('\\')[-1] else: res_name = n.split('/')[-1] failToLoad = False self.SetStatusText("Loading "+n+"...") #Change the statusbar #Find out if the result is a textual or binary file if n.lower().endswith(".txt"): #Textual file try: self.ResultFiles.append((res_name,ResultDymolaTextual(n))) except (JIOError, IOError): self.SetStatusText("Could not load "+n+".") #Change the statusbar failToLoad = True elif n.lower().endswith(".mat"): #Binary file try: self.ResultFiles.append((res_name,ResultDymolaBinary(n))) except (TypeError, IOError): self.SetStatusText("Could not load "+n+".") #Change the statusbar failToLoad = True elif n.lower().endswith(".csv"): #Binary file try: self.ResultFiles.append((res_name,ResultCSVTextual(n))) except (TypeError, IOError, ValueError): self.SetStatusText("Could not load "+n+". Trying with delimiter ','.") #Change the statusbar try: self.ResultFiles.append((res_name,ResultCSVTextual(n,delimiter=","))) except (TypeError, IOError, ValueError): self.SetStatusText("Could not load "+n+".") #Change the statusbar failToLoad = True else: self.SetStatusText("Could not load "+n+".") #Change the statusbar failToLoad = True if failToLoad: self.SetStatusText("Could not open file '" + n + "'!\n") else: self.SetStatusText("Populating tree for " +n+"...") self.tree.AddTreeNode(self.ResultFiles[-1][1], self.ResultFiles[-1][0], self.filterPanel.checkBoxTimeVarying.GetValue(), self.filterPanel.checkBoxParametersConstants.GetValue(), self.filterPanel.GetFilter()) self.ResultIndex += 1 #Increment the index self.SetStatusText("") #Change the statusbar
[docs]class VariableTree(wxCustom.CustomTreeCtrl): def __init__(self, noteBook, *args, **kwargs): super(VariableTree, self).__init__(*args, **kwargs) self.noteBook = noteBook #Add the root item self.root = self.AddRoot("Result(s)") #Root have children self.SetItemHasChildren(self.root) #Internal counter for all children self.global_id = 0 #Global ID for each loaded results (unique for each results self.local_id = 0 #Local ID for each loaded variable (unique for each variable and results) self.node_id = 0 #Node ID for each node with childrens #List of hidden children self.hidden_children = [] self.hidden_nodes = {} self.nodes = {} #Internal flags self._update_top_siblings = True
[docs] def RefreshSelectedUnder(self, item): """ Refreshes the selected items under the given item. :param `item`: an instance of L{GenericTreeItem}. """ if self._freezeCount: return if item.IsSelected(): self.RefreshLine(item) children = item.GetChildren() for child in children: if child.IsSelected(): self.RefreshLine(child)
# Workaround for bug in customtreectrl in wx making # this function not work there
[docs] def SortChildren(self, item): children = item.GetChildren() if len(children) > 1: self._dirty = True from functools import cmp_to_key children.sort(key=cmp_to_key(self.OnCompareItems))
[docs] def AddTreeNode(self, resultObject, name,timeVarying=None,parametersConstants=None,filter=None): #Freeze the window temporarely self.Freeze() #Add a new dictionary for the nodes self.nodes[self.global_id] = {} self._update_top_siblings = True child = self.AppendItem(self.root, name, data={"result_id":self.global_id, "node_id": self.node_id}) self.SetItemHasChildren(child,True) self.nodes[self.global_id][self.node_id] = {"node":child, "node_id":self.node_id, "name":name, "parent_node":self.root, "parent_node_id": -1} self.nodes[self.global_id][-1] = {"node":child, "node_id":self.node_id, "name":name, "parent_node":self.root, "parent_node_id": -2} self.node_id = self.node_id + 1 #Increment the nodes rec = {"root":child} for item in resultObject.name: spl = item.split(".") #Python object for storing data related to the variable data={} data["timevarying"] = None #resultObject.is_variable(item) #data["traj"] = resultObject.get_variable_data(item) data["traj"] = resultObject data["name"] = item data["full_name"] = item data["result_id"] = self.global_id data["variable_id"] = self.local_id = self.local_id + 1 data["result_object"] = resultObject data["item_checked"] = None if len(spl)==1: data["parents"] = child data["child"] = item data["node_id"] = self.GetPyData(child)["node_id"] self.AppendItem(child, item,ct_type=1, data=data) else: #Handle variables of type der(---.---.x) if spl[0].startswith("der(") and spl[-1].endswith(")"): spl[0]=spl[0][4:] spl[-1] = "der("+spl[-1] tmp_str = "" tmp_str_old = "" for i in range(len(spl)-1): #See if the sub directory already been added, else add tmp_str_old = tmp_str tmp_str += spl[i] try: rec[tmp_str] except KeyError: local_data = {"result_id":self.global_id, "node_id":self.node_id} if i==0: rec[tmp_str] = self.AppendItem(child, spl[i], data=local_data) local_dict = {"node":rec[tmp_str], "node_id":self.node_id, "name":spl[i], "parent_node":child, "parent_node_id": -1} self.nodes[self.global_id][self.node_id] = local_dict else: rec[tmp_str] = self.AppendItem(rec[tmp_str_old], spl[i], data=local_data) local_dict = {"node":rec[tmp_str], "node_id":self.node_id, "name":spl[i], "parent_node":rec[tmp_str_old], "parent_node_id": self.GetPyData(rec[tmp_str_old])["node_id"]} self.nodes[self.global_id][self.node_id] = local_dict self.SetItemHasChildren(rec[tmp_str],True) self.node_id = self.node_id + 1 #Increment the nodes else: data["parents"] = rec[tmp_str] data["child"] = spl[-1] data["node_id"] = self.GetPyData(rec[tmp_str],)["node_id"] self.AppendItem(rec[tmp_str], spl[-1], ct_type=1, data=data) self.SortChildren(child) #Increment global id self.global_id = self.global_id + 1 #print "Adding: ", name, "Options: ", timeVarying, parametersConstants, filter #print "Condition: ", timeVarying == False or parametersConstants == False or filter != None #Hide nodes if options are choosen if timeVarying == False or parametersConstants == False or filter != None: self.HideNodes(timeVarying,parametersConstants,filter) #Un-Freeze the window self.Thaw()
[docs] def FindLoneChildDown(self, child): """ Search for the youngest child down the tree from "child". Parameters:: child - The item from where the search should start. Returns:: child - The youngest child from the starting point. """ while True: nextItem,cookie = self.GetNextChild(child,0) if nextItem != None: child = nextItem else: break return child
[docs] def FindFirstSiblingUp(self,child,itemParent): """ Search for the first sibling of "child" going up in tree. """ while child != itemParent: nextItem = self.GetNextSibling(child) if nextItem != None: return nextItem child = self.GetItemParent(child) return child
[docs] def HideNodes(self, showTimeVarying=None, showParametersConstants=None, filter=None): """ Hide nodes depending on the input. Parameters:: showTimeVarying - Hides or Shows the time varying variables. showParametersConstants - Hides or Show the parameters. """ itemParent = self.GetRootItem() child,cookie = self.GetFirstChild(itemParent) found_child = child top_siblings = self.FindTopSiblings() #Hide items if any of the options are True if showTimeVarying == False or showParametersConstants == False or filter != None: while child != itemParent and child != None: already_hidden = False #Find the first youngest child found_child = self.FindLoneChildDown(child) #Find the first sibling up child = self.FindFirstSiblingUp(found_child, itemParent) data = self.GetPyData(found_child) if found_child in top_siblings: print("Found child in top siblings, ", self.GetItemText(found_child)) continue #print "Found child:", self.GetItemText(found_child) #print "Child: ", self.GetItemText(child), self.GetPyData(child), "Has Children: ", self.HasChildren(child) if data == None: print("Found (wrong) child:", self.GetItemText(found_child)) raise Exception try: data["timevarying"] except KeyError: print("Found (wrong (exception)) child:", self.GetItemText(found_child)) raise Exception if data["timevarying"] == None: data["timevarying"] = data["result_object"].is_variable(data["full_name"]) #Enable or disable depending on input to method if showTimeVarying == False and data["timevarying"]: self.HideItem(found_child, showTimeVarying) #Delete the parent if it has no children self.HideNodeItem(found_child) already_hidden = True if showParametersConstants == False and not data["timevarying"]: self.HideItem(found_child, showParametersConstants) #Delete the parent if it has no children self.HideNodeItem(found_child) already_hidden = True if not already_hidden and filter != None and not match(data["full_name"], filter): self.HideItem(found_child, show=False) #Delete the parent if it has no children self.HideNodeItem(found_child) #Re-add items if any of the options are True if showTimeVarying == True or showParametersConstants == True or filter != None: self.AddHiddenItems(showTimeVarying, showParametersConstants, filter)
[docs] def FindTopSiblings(self): """ Finds all the siblings one level down from root. """ if self._update_top_siblings: itemParent = self.GetRootItem() child,cookie = self.GetFirstChild(itemParent) siblings = [] while child != None: siblings.append(child) child = self.GetNextSibling(child) self._top_siblings = siblings else: siblings = self._top_siblings self._update_top_siblings = False return siblings
[docs] def AddHiddenItems(self, showTimeVarying=None, showParametersConstants=None, filter=None): #print "Adding hidden items: ", showTimeVarying, showParametersConstants, filter i = 0 while i < len(self.hidden_children): data = self.hidden_children[i] matching = False #Do not add any items! if data["timevarying"] and showTimeVarying == False or not data["timevarying"] and showParametersConstants == False: i = i+1 continue if filter != None: matching = match(data["full_name"], filter) if data["timevarying"] and showTimeVarying == True and (filter == None or filter != None and matching == True) or \ not data["timevarying"] and showParametersConstants == True and (filter == None or filter != None and matching == True): #or filter != None and match(data["full_name"], filter): if self.nodes[data["result_id"]][data["node_id"]]["node"] == None: self.AddHiddenNodes(data) #print "Adding: ", data #print "At node: ", self.nodes[data["result_id"]][data["node_id"]] item = self.AppendItem(self.nodes[data["result_id"]][data["node_id"]]["node"], data["child"],ct_type=1, data=data) if item == None: raise Exception("Something went wrong when adding the variable.") if data["item_checked"] is not None: #Item was previously checked. #print "Item was previously checked", data["item_checked"] self.noteBook.GetPage(data["item_checked"]).UpdatePlotVariableReference(-1,item,data) self.hidden_children.pop(i) i = i-1 i = i+1
[docs] def AddHiddenNodes(self, data): node = self.nodes[data["result_id"]][data["node_id"]] nodes_to_be_added = [node] while node["node"] == None and node["parent_node_id"] != -1: node = self.nodes[data["result_id"]][node["parent_node_id"]] if node["node"] != None: break nodes_to_be_added.append(node) #print "Nodes to be added: ", nodes_to_be_added for i in range(len(nodes_to_be_added)): node = nodes_to_be_added[-(i+1)] #print "Adding node: ", node, " at ", self.nodes[data["result_id"]][node["parent_node_id"]], " or ", self.nodes[data["result_id"]][-1], data local_data = {"result_id":data["result_id"], "node_id":node["node_id"]} """ if node["parent_node_id"] == -1: item = self.AppendItem(self.nodes[data["result_id"]][-1], node["name"], data=local_data) else: item = self.AppendItem(node["parent_node_id"], node["name"], data=local_data) """ item = self.AppendItem(self.nodes[data["result_id"]][node["parent_node_id"]]["node"], node["name"], data=local_data) #item = self.AppendItem(node["parent_node"], node["name"], data=local_data) self.SetItemHasChildren(item, True) self.nodes[data["result_id"]][node["node_id"]]["node"] = item
#print "Node info after adding: ", self.nodes[data["result_id"]][node["node_id"]]
[docs] def HideNodeItem(self, item): """ Deletes the parents that does not have any children """ parent = self.GetItemParent(item) top_siblings = self.FindTopSiblings() while self.HasChildren(parent) == False and parent not in top_siblings: old_parent = self.GetItemParent(parent) #Add the deleted nodes to the hidden list so that we can recreate the list #self.hidden_nodes.append(self.GetPyData(parent)) #self.hidden_nodes[self.GetPyData(parent)["node_id"]] = [self.GetPyData(parent), old_parent] #self.nodes[self.GetPyData(parent)["result_id"]][self.GetPyData(parent)["node_id"]][0] = None self.nodes[self.GetPyData(parent)["result_id"]][self.GetPyData(parent)["node_id"]]["node"] = None self.Delete(parent) parent = old_parent
[docs] def HideItem(self, item, show): data = self.GetPyData(item) if not show: self.hidden_children.append(data) self.Delete(item)
[docs] def DeleteParent(self, item): """ Delete the oldest parent of item, except root. """ if item == self.GetRootItem(): return False parentItem = self.GetItemParent(item) while parentItem != self.GetRootItem(): item = parentItem parentItem = self.GetItemParent(item) #Remove also the hidden items contained in the hidden children list data = self.GetPyData(item) i = 0 while i < len(self.hidden_children): if self.hidden_children[i]["result_id"] == data["result_id"]: self.hidden_children.pop(i) i = i-1 i = i+1 #Delete hidden nodes self.nodes.pop(data["result_id"]) self.Delete(item) #Delete the parent from the Tree
[docs] def FindIndexParent(self, item): """ Find the index of the oldest parent of item from one level down from root. """ if item == self.GetRootItem(): return -1 parentItem = item item = self.GetItemParent(parentItem) while item != self.GetRootItem(): parentItem = item item = self.GetItemParent(parentItem) root = self.GetRootItem() sibling,cookie = self.GetFirstChild(root) index = 0 while parentItem != sibling: sibling = self.GetNextSibling(sibling) index += 1 return index
[docs]class DialogLinesLegends(wx.Dialog): def __init__(self, parent, plotPage): wx.Dialog.__init__(self, parent, -1, "Lines and Legends") #Get the variables self.variables = plotPage.GetPlotVariables() #Get the settings settings = plotPage.GetSettings() #Get the lines lines = plotPage.GetLines() #First line line1 = lines[0] names = [i[2]["name"] for i in self.variables] lineStyles = ["-","--","-.",":"] colors = ["Auto","Blue","Green","Red","Cyan","Magenta","Yellow","Black","White"] lineStylesNames = ["Solid","Dashed","Dash Dot","Dotted"] markerStyles = ["None",'D','s','_','^','d','h','+','*',',','o','.','p','H','v','x','>','<'] markerStylesNames = ["None","Diamond","Square","Horizontal Line","Triangle Up","Thin Diamond","Hexagon 1","Plus","Star","Pixel","Circle", "Point","Pentagon","Hexagon 2", "Triangle Down", "X", "Triangle Right", "Triangle Left"] legendPositions = ['Hide','Best','Upper Right','Upper Left','Lower Left','Lower Right','Right','Center Left','Center Right','Lower Center','Upper Center','Center'] self.lineStyles = lineStyles self.markerStyles = markerStyles self.colors = colors #Create the legend dict from where to look up positions self.LegendDict = dict((item,i) for i,item in enumerate(legendPositions[1:])) self.LegendDict["Hide"] = -1 #Create the line style dict self.LineStyleDict = dict((item,i) for i,item in enumerate(lineStyles)) #Create the marker dict self.MarkerStyleDict = dict((item,i) for i,item in enumerate(markerStyles)) #Create the color dict self.ColorsDict = dict((item,i) for i,item in enumerate(colors)) mainSizer = wx.BoxSizer(wx.VERTICAL) bagSizer = wx.GridBagSizer(11, 11) plotLabelStatic = wx.StaticText(self, -1, "Label") plotStyleStatic = wx.StaticText(self, -1, "Style") plotMarkerStyleStatic = wx.StaticText(self, -1, "Style") plotLineStatic = wx.StaticText(self, -1, "Line") plotMarkerStatic = wx.StaticText(self, -1, "Marker") plotLegendStatic = wx.StaticText(self, -1, "Legend") plotPositionStatic = wx.StaticText(self, -1, "Position") plotWidthStatic = wx.StaticText(self, -1, "Width") plotColorStatic = wx.StaticText(self, -1, "Color") plotMarkerSizeStatic = wx.StaticText(self, -1, "Size") sizeWidth = 170 #Set the first line as default self.plotLines = wx.ComboBox(self, -1, size=(220, -1), choices=names, style=wx.CB_READONLY) self.plotLines.SetSelection(0) #Set the first line as default self.plotLineStyle = wx.ComboBox(self, -1, size=(sizeWidth, -1), choices=lineStylesNames, style=wx.CB_READONLY) self.plotMarkerStyle = wx.ComboBox(self, -1, size=(sizeWidth, -1), choices=markerStylesNames, style=wx.CB_READONLY) #Set the first label as default self.plotLineName = wx.TextCtrl(self, -1, "", style = wx.TE_LEFT , size =(sizeWidth,-1)) self.plotWidth = wx.TextCtrl(self, -1, "", style = wx.TE_LEFT, size=(sizeWidth,-1)) self.plotMarkerSize = wx.TextCtrl(self, -1, "", style = wx.TE_LEFT, size=(sizeWidth,-1)) self.plotColor = wx.ComboBox(self, -1, choices=colors, size=(sizeWidth,-1),style=wx.CB_READONLY) #Define the legend self.plotLegend = wx.ComboBox(self, -1, size=(sizeWidth, -1), choices=legendPositions, style=wx.CB_READONLY) self.plotLegend.SetSelection(plotPage.GetLegendLocation()+1) #Get the FONT font = plotLineStatic.GetFont() font.SetWeight(wx.BOLD) #Set the bold font to the sections plotLineStatic.SetFont(font) plotMarkerStatic.SetFont(font) plotLegendStatic.SetFont(font) bagSizer.Add(self.plotLines,(0,0),(1,2)) bagSizer.Add(plotLabelStatic,(1,0)) bagSizer.Add(self.plotLineName,(1,1)) bagSizer.Add(plotLineStatic,(2,0),(1,1)) bagSizer.Add(plotStyleStatic,(3,0)) bagSizer.Add(self.plotLineStyle,(3,1)) bagSizer.Add(plotWidthStatic,(4,0)) bagSizer.Add(self.plotWidth,(4,1)) bagSizer.Add(plotColorStatic,(5,0)) bagSizer.Add(self.plotColor,(5,1)) bagSizer.Add(plotMarkerStatic,(6,0),(1,1)) bagSizer.Add(plotMarkerStyleStatic,(7,0)) bagSizer.Add(self.plotMarkerStyle,(7,1)) bagSizer.Add(plotMarkerSizeStatic,(8,0)) bagSizer.Add(self.plotMarkerSize,(8,1)) bagSizer.Add(plotLegendStatic,(9,0),(1,1)) bagSizer.Add(plotPositionStatic,(10,0)) bagSizer.Add(self.plotLegend,(10,1)) #Create OK,Cancel and Apply buttons self.buttonOK = wx.Button(self, wx.ID_OK) self.buttonCancel = wx.Button(self, wx.ID_CANCEL) self.buttonApply = wx.Button(self, wx.ID_APPLY) buttonSizer = wx.StdDialogButtonSizer() buttonSizer.AddButton(self.buttonOK) buttonSizer.AddButton(self.buttonCancel) buttonSizer.AddButton(self.buttonApply) buttonSizer.Realize() #Add information to the sizers mainSizer.Add(bagSizer,0,wx.ALL|wx.EXPAND,20) mainSizer.Add(buttonSizer,1,wx.ALL|wx.EXPAND,10) #Set the main sizer to the panel self.SetSizer(mainSizer) #Set size mainSizer.Fit(self) #Set the first line as default self.ChangeLine(self.variables[0]) #Bind events self.Bind(wx.EVT_COMBOBOX, self.OnLineChange) self.buttonApply.Bind(wx.EVT_BUTTON, self.OnApply)
[docs] def OnApply(self, event): self.ApplyChanges()
[docs] def OnLineChange(self, event): if self.plotLines.FindFocus() == self.plotLines: ID = self.plotLines.GetSelection() self.ChangeLine(self.variables[ID])
[docs] def ApplyChanges(self): ID = self.plotLines.GetSelection() self.variables[ID][3].name = self.plotLineName.GetValue() self.variables[ID][3].style = self.lineStyles[self.plotLineStyle.GetSelection()] self.variables[ID][3].width = float(self.plotWidth.GetValue()) self.variables[ID][3].color = None if self.plotColor.GetSelection()==0 else self.colors[self.plotColor.GetSelection()].lower() self.variables[ID][3].marker = self.markerStyles[self.plotMarkerStyle.GetSelection()] self.variables[ID][3].markersize = float(self.plotMarkerSize.GetValue())
[docs] def ChangeLine(self, var): self.plotLineStyle.SetSelection(self.LineStyleDict[var[3].style]) self.plotMarkerStyle.SetSelection(self.MarkerStyleDict[var[3].marker]) self.plotLineName.SetValue(var[3].name) self.plotWidth.SetValue(str(var[3].width)) self.plotMarkerSize.SetValue(str(var[3].markersize)) if var[3].color == None: self.plotColor.SetSelection(0) else: self.plotColor.SetSelection(self.ColorsDict[var[3].color[0].upper()+var[3].color[1:]])
[docs] def GetValues(self): return self.LegendDict[self.plotLegend.GetValue()]
[docs]class DialogAxisLabels(wx.Dialog): def __init__(self, parent, plotPage): wx.Dialog.__init__(self, parent, -1, "Axis and Labels") settings = plotPage.GetSettings() plotXAxisStatic = wx.StaticText(self, -1, "X-Axis") plotYAxisStatic = wx.StaticText(self, -1, "Y-Axis") plotXMaxStatic = wx.StaticText(self, -1, "Max",size =(50,-1)) plotXMinStatic = wx.StaticText(self, -1, "Min",size =(50,-1)) plotTitleStatic = wx.StaticText(self, -1, "Title") plotXLabelStatic = wx.StaticText(self, -1, "Label") plotXScaleStatic = wx.StaticText(self, -1, "Scale") plotYMaxStatic = wx.StaticText(self, -1, "Max",size =(50,-1)) plotYMinStatic = wx.StaticText(self, -1, "Min",size =(50,-1)) plotYLabelStatic = wx.StaticText(self, -1, "Label") plotYScaleStatic = wx.StaticText(self, -1, "Scale") font = plotXAxisStatic.GetFont() font.SetWeight(wx.BOLD) plotXAxisStatic.SetFont(font) plotYAxisStatic.SetFont(font) self.plotYAxisMin = wx.TextCtrl(self, -1, "" if settings["YAxisMin"]==None else str(settings["YAxisMin"]), style = wx.TE_LEFT , size =(150,-1)) self.plotYAxisMax = wx.TextCtrl(self, -1, "" if settings["YAxisMax"]==None else str(settings["YAxisMax"]), style = wx.TE_LEFT , size =(150,-1)) self.plotXAxisMin = wx.TextCtrl(self, -1, "" if settings["XAxisMin"]==None else str(settings["XAxisMin"]), style = wx.TE_LEFT , size =(150,-1)) self.plotXAxisMax = wx.TextCtrl(self, -1, "" if settings["XAxisMax"]==None else str(settings["XAxisMax"]), style = wx.TE_LEFT , size =(150,-1)) self.plotTitle = wx.TextCtrl(self, -1, settings["Title"], style = wx.TE_LEFT , size =(150,-1)) self.plotXLabel = wx.TextCtrl(self, -1, settings["XLabel"], style = wx.TE_LEFT , size =(150,-1)) self.plotYLabel = wx.TextCtrl(self, -1, settings["YLabel"], style = wx.TE_LEFT , size =(150,-1)) self.plotXScale = wx.ComboBox(self, -1, size=(150, -1), choices=["Linear","Log"], style=wx.CB_READONLY) self.plotYScale = wx.ComboBox(self, -1, size=(150, -1), choices=["Linear","Log"], style=wx.CB_READONLY) self.plotXScale.SetSelection(0 if settings["XScale"]=="Linear" else 1) self.plotYScale.SetSelection(0 if settings["YScale"]=="Linear" else 1) mainSizer = wx.BoxSizer(wx.VERTICAL) bagSizer = wx.GridBagSizer(10, 10) bagSizer.Add(plotTitleStatic,(0,0)) bagSizer.Add(self.plotTitle, (0,1)) bagSizer.Add(plotXAxisStatic,(1,0),(1,1)) bagSizer.Add(plotXMinStatic,(2,0)) bagSizer.Add(self.plotXAxisMin,(2,1)) bagSizer.Add(plotXMaxStatic,(3,0)) bagSizer.Add(self.plotXAxisMax,(3,1)) bagSizer.Add(plotXLabelStatic,(4,0)) bagSizer.Add(self.plotXLabel,(4,1)) bagSizer.Add(plotXScaleStatic,(5,0)) bagSizer.Add(self.plotXScale,(5,1)) bagSizer.Add(plotYAxisStatic,(6,0),(1,1)) bagSizer.Add(plotYMinStatic,(7,0)) bagSizer.Add(self.plotYAxisMin,(7,1)) bagSizer.Add(plotYMaxStatic,(8,0)) bagSizer.Add(self.plotYAxisMax,(8,1)) bagSizer.Add(plotYLabelStatic,(9,0)) bagSizer.Add(self.plotYLabel,(9,1)) bagSizer.Add(plotYScaleStatic,(10,0)) bagSizer.Add(self.plotYScale,(10,1)) bagSizer.AddGrowableCol(1) #Create OK and Cancel buttons buttonSizer = self.CreateButtonSizer(wx.CANCEL|wx.OK) #Add information to the sizers mainSizer.Add(bagSizer,0,wx.ALL|wx.EXPAND,20) mainSizer.Add(buttonSizer,1,wx.ALL|wx.EXPAND,10) #Set the main sizer to the panel self.SetSizer(mainSizer) #Set size mainSizer.Fit(self)
[docs] def GetValues(self): xmax = self.plotXAxisMax.GetValue() xmin = self.plotXAxisMin.GetValue() ymax = self.plotYAxisMax.GetValue() ymin = self.plotYAxisMin.GetValue() title = self.plotTitle.GetValue() xlabel = self.plotXLabel.GetValue() ylabel = self.plotYLabel.GetValue() xscale = self.plotXScale.GetValue() yscale = self.plotYScale.GetValue() return xmax,xmin,ymax,ymin,title, xlabel, ylabel, xscale, yscale
[docs]class FilterPanel(wx.Panel): def __init__(self, main, parent,tree, **kwargs): wx.Panel.__init__( self, parent, **kwargs ) #Store the parent self.main = main self.parent = parent self.tree = tree self.active_filter = False mainSizer = wx.BoxSizer(wx.VERTICAL) topBox = wx.StaticBox(self, label = "Filter") topSizer = wx.StaticBoxSizer(topBox, wx.VERTICAL) flexGrid = wx.FlexGridSizer(3, 1, 0, 10) #Create the checkboxes self.checkBoxParametersConstants = wx.CheckBox(self, -1, " Parameters / Constants")#, size=(140, -1)) self.checkBoxTimeVarying = wx.CheckBox(self, -1, " Time-Varying", size=(140, -1)) self.searchBox = wx.SearchCtrl(self, -1, "Search", size=(190, -1), style=wx.TE_PROCESS_ENTER) self.searchBox.SetToolTipString("Filter the variables using a unix filename pattern matching \n" \ '(eg. "*der*"). Can also be a list of filters separated by ";"\n' \ "See http://docs.python.org/2/library/fnmatch.html.") #Check the checkboxes self.checkBoxParametersConstants.SetValue(True) self.checkBoxTimeVarying.SetValue(True) #Add the checkboxes to the flexgrid flexGrid.Add(self.checkBoxParametersConstants) flexGrid.Add(self.checkBoxTimeVarying) flexGrid.Add(self.searchBox) flexGrid.AddGrowableCol(0) #Add information to the sizers topSizer.Add(flexGrid,1,wx.ALL|wx.EXPAND,10) mainSizer.Add(topSizer,0,wx.EXPAND|wx.ALL,10) #Set the main sizer to the panel self.SetSizer(mainSizer) #Bind events self.Bind(wx.EVT_CHECKBOX, self.OnParametersConstants, self.checkBoxParametersConstants) self.Bind(wx.EVT_CHECKBOX, self.OnTimeVarying, self.checkBoxTimeVarying) self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearch, self.searchBox) self.Bind(wx.EVT_TEXT_ENTER, self.OnSearch, self.searchBox)
[docs] def GetFilter(self): if self.active_filter == True: filter = self.searchBox.GetValue().split(";") if filter[0] == "": #If the filter is empty, match all filter = ["*"] filter_list = convert_filter(filter) else: filter_list = None return filter_list
[docs] def OnSearch(self, event): self.active_filter = True self.tree.HideNodes(showTimeVarying=self.checkBoxTimeVarying.GetValue(), showParametersConstants=self.checkBoxParametersConstants.GetValue(), filter=self.GetFilter()) self.main.UpdateCheckedItemTree() if self.searchBox.GetValue() == "": self.active_filter = False
[docs] def OnParametersConstants(self, event): self.tree.HideNodes(showTimeVarying=self.checkBoxTimeVarying.GetValue(), showParametersConstants=self.checkBoxParametersConstants.GetValue(), filter=self.GetFilter()) self.main.UpdateCheckedItemTree()
[docs] def OnTimeVarying(self, event): self.tree.HideNodes(showTimeVarying=self.checkBoxTimeVarying.GetValue(), showParametersConstants=self.checkBoxParametersConstants.GetValue(), filter=self.GetFilter()) self.main.UpdateCheckedItemTree()
[docs]class Lines_Settings: def __init__(self, name=None): self.width = rcParams["lines.linewidth"] self.style = rcParams["lines.linestyle"] self.marker = rcParams["lines.marker"] self.markersize = rcParams["lines.markersize"] self.color = None self.name = name
[docs]class PlotPanel(wx.Panel): def __init__(self, parent, grid=False,move=True,zoom=False, **kwargs): wx.Panel.__init__( self, parent, **kwargs ) #Initialize matplotlib self.figure = Figure(facecolor = 'white') self.canvas = FigureCanvasWxAgg(self, -1, self.figure) self.subplot = self.figure.add_subplot( 111 ) self.parent = parent self.settings = {} self.settings["Grid"] = grid self.settings["Zoom"] = zoom self.settings["Move"] = move self.SetDefaultSettings() #Set the default settings self.plotVariables = [] self._resizeflag = False self._SetSize() self.DrawSettings() #Bind events self.Bind(wx.EVT_IDLE, self.OnIdle) self.Bind(wx.EVT_SIZE, self.OnSize) #Bind event for resizing (must bind to canvas) self.canvas.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) self.canvas.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) self.canvas.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) self.canvas.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) self.canvas.Bind(wx.EVT_ENTER_WINDOW, self.OnEnterWindow) self.canvas.Bind(wx.EVT_MOTION, self.OnMotion) self.canvas.Bind(wx.EVT_LEFT_DCLICK, self.OnPass) self._mouseLeftPressed = False self._mouseMoved = False
[docs] def SetDefaultSettings(self): self.settings["Title"] = "" self.settings["XLabel"] = "Time [s]" self.settings["YLabel"] = "" self.settings["XAxisMax"] = None self.settings["XAxisMin"] = None self.settings["YAxisMax"] = None self.settings["YAxisMin"] = None self.settings["XScale"] = "Linear" self.settings["YScale"] = "Linear" self.settings["LegendPosition"] = 0 #"Best" position
[docs] def AddPlotVariable(self, ID, item, data): lineSettings = Lines_Settings(data["name"]) self.plotVariables.append([ID,item,data,lineSettings])
[docs] def GetPlotVariables(self): return self.plotVariables
[docs] def DeleteAllPlotVariables(self): self.plotVariables = []
[docs] def UpdatePlotVariableReference(self, ID,item,data): self.DeletePlotVariable(local_id=data["variable_id"]) self.AddPlotVariable(ID,item,data)
[docs] def DeletePlotVariable(self, local_id=None, global_id=None): if local_id != None: for i,var in enumerate(self.plotVariables): if var[2]["variable_id"] == local_id: self.plotVariables.pop(i) break if global_id != None: j = 0 while j < len(self.plotVariables): if self.plotVariables[j][2]["result_id"] == global_id: self.plotVariables.pop(j) j = j-1 j = j+1 if j==len(self.plotVariables): break
[docs] def OnPass(self, event): pass
[docs] def OnMotion(self, event): if self._mouseLeftPressed: #Is the mouse pressed? self._mouseMoved = True self._newPos = event.GetPosition() if self.settings["Move"]: self.DrawMove() if self.settings["Zoom"]: self.DrawRectZoom()
[docs] def DrawZoom(self): try: y0 = self._figureMin[1][1]-self._lastZoomRect[1] x0 = self._lastZoomRect[0]-self._figureMin[0][0] w = self._lastZoomRect[2] h = self._lastZoomRect[3] fullW = self._figureMin[1][0]-self._figureMin[0][0] fullH = self._figureMin[1][1]-self._figureMin[0][1] if w < 0: x0 = x0 + w x0 = max(x0, 0.0) y0 = max(y0, 0.0) plotX0 = self.subplot.get_xlim()[0] plotY0 = self.subplot.get_ylim()[0] plotW = self.subplot.get_xlim()[1]-self.subplot.get_xlim()[0] plotH = self.subplot.get_ylim()[1]-self.subplot.get_ylim()[0] self.settings["XAxisMin"] = plotX0+abs(x0/fullW*plotW) self.settings["XAxisMax"] = plotX0+abs(x0/fullW*plotW)+abs(w/fullW*plotW) self.settings["YAxisMin"] = plotY0+abs(y0/fullH*plotH) self.settings["YAxisMax"] = plotY0+abs(y0/fullH*plotH)+abs(h/fullH*plotH) self.DrawRectZoom(drawNew=False) #Delete the last zoom rectangle self.DrawSettings() except AttributeError: self.DrawRectZoom(drawNew=False) #Delete the last zoom rectangle
[docs] def DrawMove(self): x0,y0 = self._originalPos x1,y1 = self._newPos fullW = self._figureMin[1][0]-self._figureMin[0][0] fullH = self._figureMin[1][1]-self._figureMin[0][1] plotX0,plotY0,plotW,plotH = self._plotInfo self.settings["XAxisMin"] = plotX0+(x0-x1)/fullW*plotW self.settings["XAxisMax"] = plotX0+plotW+(x0-x1)/fullW*plotW self.settings["YAxisMin"] = plotY0+(y1-y0)/fullH*plotH self.settings["YAxisMax"] = plotY0+plotH+(y1-y0)/fullH*plotH self.DrawSettings()
[docs] def DrawRectZoom(self, drawNew=True): dc = wx.ClientDC(self.canvas) dc.SetLogicalFunction(wx.XOR) wbrush =wx.Brush(wx.Colour(255,255,255), wx.TRANSPARENT) wpen =wx.Pen(wx.Colour(200, 200, 200), 1, wx.SOLID) dc.SetBrush(wbrush) dc.SetPen(wpen) dc.ResetBoundingBox() dc.BeginDrawing() y1 = min(max(self._newPos[1],self._figureMin[0][1]),self._figureMin[1][1]) y0 = min(max(self._originalPos[1],self._figureMin[0][1]),self._figureMin[1][1]) x1 = min(max(self._newPos[0],self._figureMin[0][0]),self._figureMin[1][0]) x0 = min(max(self._originalPos[0],self._figureMin[0][0]),self._figureMin[1][0]) if y1 > y0: y0, y1 = y1, y0 if x1 < y0: x0, x1 = x1, x0 w = x1 - x0 h = y1 - y0 rectZoom = int(x0), int(y0), int(w), int(h) try: self._lastZoomRect except AttributeError: pass else: dc.DrawRectangle(*self._lastZoomRect) #Erase last if drawNew: self._lastZoomRect = rectZoom dc.DrawRectangle(*rectZoom) else: try: del self._lastZoomRect except AttributeError: pass dc.EndDrawing()
#dc.Destroy()
[docs] def OnLeftDown(self, event): self._mouseLeftPressed = True #Mouse is pressed #Capture mouse position self._originalPos = event.GetPosition() #Capture figure size self._figureRatio = self.subplot.get_position().get_points() self._figureSize = (self.canvas.figure.bbox.width,self.canvas.figure.bbox.height) self._figureMin = [(round(self._figureSize[0]*self._figureRatio[0][0]),round(self._figureSize[1]*self._figureRatio[0][1])), (round(self._figureSize[0]*self._figureRatio[1][0]),round(self._figureSize[1]*self._figureRatio[1][1]))] #Capture current plot plotX0 = self.subplot.get_xlim()[0] plotY0 = self.subplot.get_ylim()[0] plotW = self.subplot.get_xlim()[1]-self.subplot.get_xlim()[0] plotH = self.subplot.get_ylim()[1]-self.subplot.get_ylim()[0] self._plotInfo = (plotX0, plotY0, plotW, plotH)
[docs] def OnLeftUp(self, event): self._mouseLeftPressed = False #Mouse is not pressed if self._mouseMoved: self._mouseMoved = False if self.settings["Zoom"]: self.DrawZoom() if self.settings["Move"]: self.DrawMove()
[docs] def OnLeaveWindow(self, event): #Change cursor if self._mouseLeftPressed: self._mouseLeftPressed = False #Mouse not pressed anymore self._mouseMoved = False if self.settings["Zoom"]: self.DrawZoom() if self.settings["Move"]: self.DrawMove()
[docs] def OnEnterWindow(self, event): #Change cursor self.UpdateCursor()
[docs] def OnRightDown(self, event): """ On right click, resize the plot. """ self.ReSize()
[docs] def ReSize(self): self.UpdateSettings(axes=[None,None,None,None]) self.DrawSettings()
[docs] def OnSize(self, event): self._resizeflag = True
[docs] def OnIdle(self, event): if self._resizeflag: self._resizeflag = False self._SetSize()
def _SetSize(self): pixels = tuple(self.GetClientSize()) #self.SetSize(pixels) #GENERATES INFINITELY EVENTS ON UBUNTU self.canvas.SetSize(pixels) self.figure.set_size_inches(float(pixels[0])/self.figure.get_dpi(), float(pixels[1])/self.figure.get_dpi()) #def Draw(self, variables=[]):
[docs] def Draw(self): self.subplot.clear() self.subplot.hold(True) for i in self.plotVariables: traj = i[2]["traj"].get_variable_data(i[2]["full_name"]) if i[3].color is None: #self.subplot.plot(i[2]["traj"].t, i[2]["traj"].x,label=i[3].name,linewidth=i[3].width,marker=i[3].marker,linestyle=i[3].style,markersize=i[3].markersize) self.subplot.plot(traj.t, traj.x,label=i[3].name,linewidth=i[3].width,marker=i[3].marker,linestyle=i[3].style,markersize=i[3].markersize) else: #self.subplot.plot(i[2]["traj"].t, i[2]["traj"].x,label=i[3].name,linewidth=i[3].width,marker=i[3].marker,linestyle=i[3].style,markersize=i[3].markersize,color=i[3].color) self.subplot.plot(traj.t, traj.x,label=i[3].name,linewidth=i[3].width,marker=i[3].marker,linestyle=i[3].style,markersize=i[3].markersize,color=i[3].color) self.DrawSettings()
[docs] def GetLines(self): return self.subplot.get_lines()
[docs] def GetLegendLocation(self): res = self.subplot.get_legend() if res is None: return -1 else: return res._loc
[docs] def Save(self, filename): """ Saves the current figure. Parameters:: filename - The name of the to be saved plot. """ self.figure.savefig(filename)
[docs] def DrawSettings(self): """ Draws the current settings onto the Plot. """ self.subplot.grid(self.settings["Grid"]) #Draw label settings self.subplot.set_title(self.settings["Title"]) self.subplot.set_xlabel(self.settings["XLabel"]) self.subplot.set_ylabel(self.settings["YLabel"]) #Draw Scale settings self.subplot.set_xscale(self.settings["XScale"]) self.subplot.set_yscale(self.settings["YScale"]) if len(self.plotVariables) != 0 and self.settings["LegendPosition"] != -1: self.subplot.legend(loc=self.settings["LegendPosition"]) #Draw axis settings if self.settings["XAxisMin"] != None: #self.subplot.set_xlim(left=self.settings["XAxisMin"]) self.subplot.set_xlim(xmin=self.settings["XAxisMin"]) if self.settings["XAxisMax"] != None: #self.subplot.set_xlim(right=self.settings["XAxisMax"]) self.subplot.set_xlim(xmax=self.settings["XAxisMax"]) if self.settings["XAxisMax"] == None and self.settings["XAxisMin"] == None: self.subplot.set_xlim(None,None) self.subplot.set_autoscalex_on(True) #self.subplot.autoscale(axis="x") self.subplot.autoscale_view(scalex=True) if self.settings["YAxisMin"] != None: #self.subplot.set_ylim(bottom=self.settings["YAxisMin"]) self.subplot.set_ylim(ymin=self.settings["YAxisMin"]) if self.settings["YAxisMax"] != None: #self.subplot.set_ylim(top=self.settings["YAxisMax"]) self.subplot.set_ylim(ymax=self.settings["YAxisMax"]) if self.settings["YAxisMax"] == None and self.settings["YAxisMin"] == None: self.subplot.set_ylim(None,None) self.subplot.set_autoscaley_on(True) #self.subplot.autoscale(axis="y") #METHOD DOES NOT EXIST ON VERSION LESS THAN 1.0 self.subplot.autoscale_view(scaley=True) #Draw self.canvas.draw()
[docs] def UpdateSettings(self, grid=None, title=None, xlabel=None, ylabel=None, axes=None, move=None, zoom=None, xscale=None, yscale=None, legendposition=None): """ Updates the settings dict. """ if grid !=None: self.settings["Grid"] = grid if title !=None: self.settings["Title"] = title if xlabel !=None: self.settings["XLabel"] = xlabel if ylabel !=None: self.settings["YLabel"] = ylabel if axes != None: self.settings["XAxisMin"]=axes[0] self.settings["XAxisMax"]=axes[1] self.settings["YAxisMin"]=axes[2] self.settings["YAxisMax"]=axes[3] if move != None: self.settings["Move"] = move if zoom != None: self.settings["Zoom"] = zoom if xscale != None: self.settings["XScale"] = xscale if yscale != None: self.settings["YScale"] = yscale if legendposition != None: self.settings["LegendPosition"] = legendposition
[docs] def UpdateCursor(self): if self.settings["Move"]: cursor = wx.StockCursor(wx.CURSOR_HAND) self.canvas.SetCursor(cursor) if self.settings["Zoom"]: cursor = wx.StockCursor(wx.CURSOR_CROSS) self.canvas.SetCursor(cursor)
[docs] def GetSettings(self): """ Returns the settigns of the current plot. """ return self.settings
[docs]def startGUI(filename=None): """ Starts GUI. If a filename is provided, that file is loaded into the GUI on startup. """ #Start GUI app = wx.App(False) gui = MainGUI(None, -1,filename) app.MainLoop()
if __name__ == '__main__': startGUI()