def on_button_FromData_clicked(self):
        try:
            dataService = DataService()
            expData = dataService.get_experimental_data()
            timepointSet = set()
            if expData:
                for dataSet in expData.values():
                    if not dataSet.isSelected():
                        continue
                    if dataSet.dataDescriptors:
                        for dataDescriptor in dataSet.dataDescriptors:
                            timepointSet.add(float(dataDescriptor))
                    for entityData in dataSet.getData().values():
                        if not entityData.isSelected():
                            continue
                        if entityData.dataDescriptors:
                            for dataDescriptor in entityData.dataDescriptors:
                                timepointSet.add(float(dataDescriptor))
            self.timepoints = list(timepointSet)
            self.timepoints.sort()
            timepointsStr = str(self.timepoints).replace(",", " ").strip("[").strip("]")

            if not timepointsStr:
                timepointsStr = "No timepoint data."

            self.plainTextEdit_Timepoints.clear()
            self.plainTextEdit_Timepoints.insertPlainText(timepointsStr)
        except Exception, e:
            logging.error("Could not get timepoints from data. Error: %s" % e)
Beispiel #2
0
    def on_actionAddToExperimentalData_triggered(self):
        """
        Adds the currently displayed data and adds it to the experimental data.
        This is usually only useful if you want to want to use simulation results (which can then be perturbed)
        as input for other tools like parameter value estimation.
        """
        logging.info("Adding current data to Experimental Data...")
        dataService = DataService()
        expDataSet = DataSet(None)
        expDataSet.setId("Pseudo-Experimental Data")
        expDataSet.setType(services.dataservice.EXPERIMENTAL)
        expDataSet.setSelected(True)
        first = True
        for key, itemList in self.data.items():
            for oldItem in itemList:
                item = oldItem.copy()

                if type(item.getId()) != str:
                    logging.debug(
                        "TableWidgetController.on_actionAddToExperimentalData_triggered(): Encountered item with non-string as id: %s. Skipping."
                        % str(item.getId())
                    )
                    continue
                #                item.setId(item.getId() + "_syn")
                item.setType(datamanagement.entitydata.TYPE_EXPERIMENTAL)
                item.setAssociatedDataSet(expDataSet)
                expDataSet.data[key] = item  # TODO: Handle mutliple EntityData objects correctly
                if first:
                    expDataSet.dataDescriptors = item.dataDescriptors[:]
                    expDataSet.dataDescriptorUnit = item.dataDescriptorUnit
                    first = False
        dataService.add_data(expDataSet)
    def __init__(self, parent, parkinController):
        super(DataImportWidget, self).__init__(parent)
        self.setupUi(self)

        self.currentExpDataFilename = None
        self.dataService = DataService()
        self.parkinController = parkinController
Beispiel #4
0
    def on_button_FromData_clicked(self):
        try:
            dataService = DataService()
            expData = dataService.get_experimental_data()
            timepointSet = set()
            if expData:
                for dataSet in expData.values():
                    if not dataSet.isSelected():
                        continue
                    if dataSet.dataDescriptors:
                        for dataDescriptor in dataSet.dataDescriptors:
                            timepointSet.add(float(dataDescriptor))
                    for entityData in dataSet.getData().values():
                        if not entityData.isSelected():
                            continue
                        if entityData.dataDescriptors:
                            for dataDescriptor in entityData.dataDescriptors:
                                timepointSet.add(float(dataDescriptor))
            self.timepoints = list(timepointSet)
            self.timepoints.sort()
            timepointsStr = str(self.timepoints).replace(
                ",", " ").strip("[").strip("]")

            if not timepointsStr:
                timepointsStr = "No timepoint data."

            self.plainTextEdit_Timepoints.clear()
            self.plainTextEdit_Timepoints.insertPlainText(timepointsStr)
        except Exception, e:
            logging.error("Could not get timepoints from data. Error: %s" % e)
Beispiel #5
0
    def on_actionAddToExperimentalData_triggered(self):
        '''
        Adds the currently displayed data and adds it to the experimental data.
        This is usually only useful if you want to want to use simulation results (which can then be perturbed)
        as input for other tools like parameter value estimation.
        '''
        logging.info("Adding current data to Experimental Data...")
        dataService = DataService()
        expDataSet = DataSet(None)
        expDataSet.setId("Pseudo-Experimental Data")
        expDataSet.setType(services.dataservice.EXPERIMENTAL)
        expDataSet.setSelected(True)
        first = True
        for key, list in self.data.items():
            for oldItem in list:
                item = oldItem.copy()

                if type(item.getId()) != str:
                    logging.debug(
                        "TableWidgetController.on_actionAddToExperimentalData_triggered(): Encountered item with non-string as id: %s. Skipping."
                        % str(item.getId()))
                    continue
                #                item.setId(item.getId() + "_syn")
                item.setType(datamanagement.entitydata.TYPE_EXPERIMENTAL)
                item.setAssociatedDataSet(expDataSet)
                expDataSet.data[
                    key] = item  # TODO: Handle mutliple EntityData objects correctly
                if first:
                    expDataSet.dataDescriptors = item.dataDescriptors[:]
                    expDataSet.dataDescriptorUnit = item.dataDescriptorUnit
                    first = False
        dataService.add_data(expDataSet)
Beispiel #6
0
 def _initialize(self):
     self.dataService = DataService()
     self.experimentalData = None
     self.simulationData = None
     self.dataSourceTableModel = None
     self.dataSourceIDs = []
     self.allData = None
     self.dataSources = None
 def _initialize(self):
     self.dataService = DataService()
     self.experimentalData = None
     self.simulationData = None
     self.dataSourceTableModel = None
     #        self.dataSourceTableView = QTableView(None)
     #        self.DataIndexToDataID = {}
     self.dataSourceIDs = []
     self.allData = None
     self.dataSources = None
Beispiel #8
0
 def __init__(self, parent, parkinController):
     super(DataImportWidget, self).__init__(parent)
     self.setupUi(self)
     
     self.currentExpDataFilename = None
     self.dataService = DataService()
     self.parkinController = parkinController
Beispiel #9
0
    def on_buttonSaveAs_clicked(self):
        logging.debug("Saving data. Displaying file chooser...")
        file_choices = "Tab-Delimited Text File *.txt (*.txt)"

        path = unicode(
            QFileDialog.getSaveFileName(self, 'Save file', '',
                                        file_choices)[0])

        if not path.endswith(".txt"):
            path += ".txt"

        if path:
            if not self.dataService:
                self.dataService = DataService()

            id = self.data.getId()
            self.dataService.save_data_as_csv(id, path)
            logging.info("Saved data to %s" % path)
 def _initialize(self):
     self.dataService = DataService()
     self.experimentalData = None
     self.simulationData = None
     self.dataSourceTableModel = None
     #        self.dataSourceTableView = QTableView(None)
     #        self.DataIndexToDataID = {}
     self.dataSourceIDs = []
     self.allData = None
     self.dataSources = None
Beispiel #11
0
    def on_buttonSaveAs_clicked(self):
        logging.debug("Saving data. Displaying file chooser...")
        file_choices = "Tab-Delimited Text File *.txt (*.txt)"

        path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '', file_choices)[0])

        if not path.endswith(".txt"):
            path += ".txt"

        if path:
            if not self.dataService:
                self.dataService = DataService()

            id = self.data.getId()
            self.dataService.save_data_as_csv(id, path)
            logging.info("Saved data to %s" % path)
Beispiel #12
0
class BioParkinController(QMainWindow, Ui_MainWindow):
    """
    This is the heart of BioParkin. It sets up the general UI
    (MainWindow, some Views, ...), handles creation and management of
    individual network windows, and instantiates needed services
    (for easy access to data, status bar, ...).

    This class inherits from QMainWindow for its functionality and from
    the (automatically generated) Ui_MainWindow for the design of the UI
    (including the self.setupUi() method).

    @param parent: The standard Qt parent.
    @type parent: QWidget

    @organization: Zuse Insitute Berlin
    """

    __version__ = "1.2.27"
    __author__ = "Moritz Wade & Thomas Dierkes"
    __contact__ = "[email protected] or [email protected]"
    __copyright__ = "Zuse Institute Berlin 2011"

    newNetworkWindowCreated = Signal()
    networkWindowRaised = Signal()
    activeModelChanged = Signal(ModelController)
    modelClosed = Signal(ModelController)

    def __init__(self, args, parent=None):
        """
        This initialization does a lot of stuff. :)

        * State variables are set up
        * Views are created and tied to UI parts (e.g. Docks)
        * Logging is set up
        * Services (StatusBar, Data, ...) are started
        * Necessary slots are connected

        """
        super(BioParkinController, self).__init__(parent)

        # for locale testing
        #locale.setlocale(locale.LC_ALL, 'de_DE')
        #        locale.setlocale(locale.LC_ALL, 'deu_deu')

        self.startTime = time.localtime()

        # set file logger
        self.rotatingFileHandler = logging.handlers.RotatingFileHandler(
            _LOG_FILENAME, maxBytes=1000000, backupCount=5)
        self.rotatingFileHandler.setFormatter(
            logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
        self.logger = logging.getLogger()  #gets root logger
        self.logger.addHandler(self.rotatingFileHandler)

        # Status bar logger
        self.statusBarLoggingHandler = StatusBarLoggingHandler()
        self.statusBarLoggingHandler.setLevel(
            logging.INFO)  # only log on info level
        self.logger.addHandler(self.statusBarLoggingHandler)

        # parse command line arguments
        parser = OptionParser()
        parser.add_option(
            "-d",
            "--debug",
            action="store_true",
            dest=OPTION_DEBUG,
            default=False,
            help="Include debugging information in console and file log")
        self.options, args = parser.parse_args()

        self.optionsService = OptionsService()
        self.optionsService.setDebug(self.options.debug)

        # set logging options
        if self.options.debug:
            self.logger.setLevel(logging.DEBUG)
            self.rotatingFileHandler.setLevel(logging.DEBUG)
            logging.info("Debug logging active.")
        else:
            self.logger.setLevel(logging.INFO)
            self.rotatingFileHandler.setLevel(logging.INFO)
            logging.info("Debug logging not active.")

        logging.info("Starting BioPARKIN... %s" % self.startTime)

        ##### LOGGING #####
        logging.info("BioPARKIN started (version %s)" %
                     BioParkinController.__version__)
        logging.info("Command line arguments: %s" % args)
        logging.info("Python version: %s" % sys.version)
        logging.info("PySide version: %s" % PySide.__version__)
        logging.info("PARKINcpp version: %s" % PARKINCPP_DOTTED_VERSION)
        logging.info("libSBML version: %s" % LIBSBML_DOTTED_VERSION)
        logging.info("Matplotlib version: %s" % matplotlib.__version__)
        #        logging.info("NetworkX version: %s" % networkx.__version__)
        logging.info("Python Image Library version: %s" % Image.VERSION)

        self.setupUi(self)
        self._mdiArea.hide()
        self.setWindowTitle("BioPARKIN v%s" % BioParkinController.__version__)

        # restore previous settings
        settings = QSettings()
        try:
            self.recentFiles = settings.value("RecentFiles", [])

            # handles the case if only one file is in the "list" in Linux (it's retrieved as unicode string in this case)
            if type(self.recentFiles) is str or type(
                    self.recentFiles) is unicode:
                self.recentFiles = [self.recentFiles]

            logging.info("Recently opened files: %s" % self.recentFiles)
        except:
            logging.warning(
                "Can't access list of recently opened files. Resetting the list."
            )
            self.recentFiles = []

        self.updateFileMenu()
        self.aboutDialog = None

        geometry = settings.value("Geometry")
        if geometry:
            self.restoreGeometry(geometry)

        state = settings.value("MainWindow/State")
        if state:
            self.restoreState(state)

        self.ModelControllers = {}
        #        self.SubWindowToModelControllers = {}
        #        self.NetworkWindowCount = 0
        #        self.ActiveNetworkWindow = None
        self.ActiveModelController = None
        #        self.networkSubWindows = {}

        self.integrator = None
        self.odeViewer = None

        self.ModelView = ModelView(self.masterDetailSplitter, self)
        self.ModelTreeView = SBMLEntityWidget(self.masterDetailSplitter)
        self.EntityTableView = EntityTableView(self.masterDetailSplitter)

        self.mainWindowViews = [self.ModelTreeView, self.EntityTableView
                                ]  #used to iterate over Views

        # set up Data Service and Data Viewer
        datahandling.parkinController = self
        self.dataService = DataService()

        # debugging#############
        BASE_PATH = reduce(
            lambda l, r: l + os.path.sep + r,
            os.path.dirname(os.path.realpath(__file__)).split(
                os.path.sep)[:-1])

        # add ../../templates (relative to the file (!) and not to the CWD)
        dataPath = os.path.join(BASE_PATH, "data")
        #######################

        self.SimulationWorkbenchController = SimulationWorkbenchController(
            parent=None, parkinController=self)
        self.mainTabWidget.addTab(self.SimulationWorkbenchController,
                                  "Workbench")

        # hook up status bar with progress service (that threads can connect to)
        self.statusBarService = StatusBarService(self.statusBar(
        ))  # first time, service is instantiated => give statusBar reference!
        self.progressBarService = ProgressBarService(self,
                                                     self.statusBarService)

        self.statusBarLoggingHandler.setStatusBar(self.statusBarService)

        self.warningsService = WarningService.getInstance()
        self.warningsDialog = WarningsDialog(self, self.actionShow_Warnings,
                                             self.warningsService)

        # register signals
        self.activeModelChanged.connect(self.on_activeModelChanged)
        self.modelClosed.connect(self.on_modelClosed)
        self.menuFile.aboutToShow.connect(self.updateFileMenu)

        # for debugging
        self.dummyThread = None

        try:  # try to set correct taskbar icon in Windows 7
            myappid = 'ZIB.BioPARKIN'  # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(
                myappid)
        except:
            pass

    def updateFileMenu(self):
        """
        Updates the file menu dynamically, so that recent files can be shown.
        """
        self.menuFile.clear()
        #        self.menuFile.addAction(self.actionNew)    # disable for now
        self.menuFile.addAction(self.actionOpen)
        self.menuFile.addAction(self.actionSave)
        self.menuFile.addAction(self.actionSave_as)
        self.menuFile.addAction(self.actionClose_Model)

        recentFiles = []
        for filename in self.recentFiles:
            if QFile.exists(filename):
                recentFiles.append(filename)

        if len(self.recentFiles) > 0:
            self.menuFile.addSeparator()
            for i, filename in enumerate(recentFiles):
                action = QAction(
                    "&%d %s" % (i + 1, QFileInfo(filename).fileName()), self)
                action.setData(filename)
                action.setStatusTip("Opens recent file %s" %
                                    QFileInfo(filename).fileName())
                action.setShortcut(QKeySequence(Qt.CTRL | (Qt.Key_1 + i)))
                action.triggered.connect(self.load_model)
                self.menuFile.addAction(action)

        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionQuit)

    def new_model(self):
        """
        Not yet supported.
        """
        pass

    def load_model(self, filename=None):
        """
        Loads a given SBML file, thereby creating a new subwindow
        on the main MDI Area.
        If filename is None, it creates a new model.

        There are a lot of reference variables, so that the system knows the
        currently active subwindow, etc.

        @param filename: The filename of the model. If None, a new model is created.
        @type filename: str
        """
        if not filename:
            action = self.sender()
            if type(action) == QAction:
                filename = action.data()
            else:
                return

        # note: this has been (temporarily added) to allow only one file to be open at the same time
        # We will probably change this behaviour again later, once we have decided how to handle
        # multiple-model results, etc. intelligently
        if len(self.ModelControllers) > 0:

            # show warning dialog
            msgBox = QMessageBox()
            infoText =\
            """<b>Another model is currently loaded.</b><br>
            """
            msgBox.setText(infoText)
            infoTextShort = "Do you want to save the current model (you will be prompted to enter a new filename)?"
            msgBox.setInformativeText(infoTextShort)
            msgBox.setWindowTitle(infoTextShort)
            msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard)
            msgBox.setDefaultButton(QMessageBox.Save)
            msgBox.setIcon(QMessageBox.Warning)
            clickedButton = msgBox.exec_()

            if clickedButton == QMessageBox.Save:
                self.actionSave_as.trigger()

            for modelController in self.ModelControllers.values(
            ):  # close all models (in theory, there should be only one :)
                self.modelClosed.emit(modelController)

#        self.NetworkWindowCount += 1
#        self.setStatusTip("Opening file %s..." % filename)
        self.statusBar().showMessage("Opening file %s..." % filename, 2000)
        modelController = ModelController(filename=filename,
                                          views=self.mainWindowViews)

        #        # create NetworkViewController
        #        networkViewController = NetworkViewController(modelController=modelController)
        #        networkView = networkViewController.createNetworkView(self) # sets networkController.networkView internally
        #        networkView.setMinimumSize(400, 300)
        #        modelController.setViews(networkViewController=networkViewController)

        #        # Create Subwindow to hold the NetworkView
        #        subWindow = QMdiSubWindow(parent=self._mdiArea)
        #        networkViewController.subWindow = subWindow
        #        subWindow.setAttribute(Qt.WA_DeleteOnClose)
        #        subWindow.setWidget(networkView)
        #        subWindow.setOption(QMdiSubWindow.RubberBandResize, True)
        #        self._mdiArea.addSubWindow(subWindow)
        #        subWindow.activateWindow()
        #        subWindow.show()    # important!
        #        networkView.show()

        # handle references
        filename = modelController.filename
        #        self.SubWindowToModelControllers[subWindow] = modelController
        #        self.networkSubWindows[modelController] = subWindow #networkView
        self.ModelControllers[filename] = modelController
        #        self.ActiveNetworkWindow = networkWindow
        self.ActiveModelController = modelController

        #        self.connectNetworkWindowSignals(networkView, subWindow)

        # emit custom Signal so that e.g. Simulationworkbench are notified of the new subwindow
        #        self.newNetworkWindowCreated.emit()
        self.activeModelChanged.emit(modelController)

        # handle recent files list
        if filename in self.recentFiles:
            self.recentFiles.remove(filename)
        self.recentFiles.insert(0, filename)
        if len(self.recentFiles
               ) > NUM_RECENT_FILES:  # cap list at length of NUM_RECENT_FILES
            self.recentFiles = self.recentFiles[:NUM_RECENT_FILES]

#    def getMdiArea(self):
#        return self._mdiArea

#    @Slot("QWidget")
#    def connectNetworkWindowSignals(self, networkWindow, subWindow):
#        """
#        Connect the signals of network windows (e.g. network is about to be destroyed, etc.)
#
#        @param networkWindow: A network view
#        @type networkWindow: NetworkView
#
#        @param subWindow: A Qt QMdiArea sub window
#        @type subWindow: QMdiSubWindow
#        """
#        #self.connect(button3, SIGNAL("clicked()"),    lambda who="Three": self.anyButton(who))
#
#        self.connect(networkWindow, SIGNAL("destroyed()"),
#                     lambda who=networkWindow: self.on_networkwindow_destroyed(who))

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('Filename'):
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        """
        Handles the drop event if the user "drops" a file somewhere within BioPARKIN's window.
        """
        # get filename
        uris = event.mimeData().urls(
        )  # support opening several models at once

        # note: uncomment this, to enable drag'n'dropping of multiple models again
        #        for uri in uris:
        #            filename = uri.toLocalFile()
        #            #open file
        #            self.load_model(filename)
        filename = uris[0].toLocalFile()
        self.load_model(filename)
        if len(uris) > 1:
            logging.info(
                "You dragged more than one model to BioPARKIN. Currently, only one model is supported to be opened at the same time. Only the first dragged model was loaded."
            )

    def on_modelClosed(self, modelController):
        """
        Whenever the Signal self.modelClosed is emitted, this
        method is called.
        It removes the modelController of the closed model from
        the management dictionary and updates all local Views.
        """
        if not modelController:
            logging.info("Can't close the model. No model selected.")

            #### abusing this place for testing ####
            #            self.dummyThread = DummyProgressThread()
            #            self.progressBarService.connect_to_thread(self.dummyThread)
            #            self.dummyThread.start()

            #            self.dummyThread = DummyThrobberThread()
            #            self.progressBarService.connect_to_thread(self.dummyThread)
            #            self.dummyThread.start()

            ########################################

            return
        if self.ModelControllers.has_key(
                modelController.filename
        ):  # we do this to remove the model controller from the management dict
            self.ModelControllers.pop(modelController.filename)

        if len(self.ModelControllers) == 0:
            # 26.07.12 td: the next line has been commented out
            self.dataService.remove_all_simulated_data()
            self.ActiveModelController = None
            for view in self.mainWindowViews:
                view.setModel(None)

#    def on_networkwindow_destroyed(self, networkWindow):
#        """
#        This is a slot. It's called to clean things up when a network
#        window is destroyed. Basically, it just gets the correct ModelController
#        and passes it on using the modelClosed signal of the BioPARKIN controller.
#
#        @param networkWindow: A network view
#        @type networkWindow: NetworkView
#        """
#        logging.debug("Destroying a NetworkWindow: %s" % networkWindow)
#        modelController = networkWindow.controller.modelController
#        self.modelClosed.emit(modelController)
#
#    def closeNetworkWindow(self, modelController):
#        if self.networkSubWindows.has_key(modelController): # might have been removed already
#            self.networkSubWindows.pop(modelController).close() #removes window from dict and closes it

    def on_activeModelChanged(self, activeModelController):
        """
        Whenever the active model changes, the appropriate Signal
        self.activeModelChanged should be emitted. When that is done, this method
        is called.
        """
        logging.info("Active Model: %s" % activeModelController.filename)
        if activeModelController is not None:
            self.ActiveModelController = activeModelController
            for view in self.mainWindowViews:
                view.setModel(self.ActiveModelController.proxyModel,
                              mainModel=self.ActiveModelController.sbmlModel)
                view.setSelectionModel(
                    self.ActiveModelController.selectionModel)

#    def selectNetworkView(self, modelController):
#        subwindow = self.networkSubWindows[modelController]
##        subwindow.show()
#        subwindow.raise_()
#        subwindow.activateWindow()
##        subwindow.setFocus()

#    def on_networkwindow_raised(self, subWindow):
#        """
#        This is a slot. It's called when a network window gets focus.
#        Some references have to be set, and most importantly, all the Views
#        have to be switched so that they use the data model behind the
#        newly focused network window.
#
#        @param subWindow: A sub window
#        @type subWindow: QMdiSubWindow
#        """
#        if subWindow is None:
#            return
#        if not self.SubWindowToModelControllers.has_key(subWindow):
#            return
#
#        activeModelController = self.SubWindowToModelControllers[subWindow]
##        self.ActiveNetworkWindow = self.ActiveModelController.getNetworkView()
#
##        self.on_activeModelChanged()
#        self.activeModelChanged.emit(activeModelController)
##        self.networkWindowRaised.emit()
#
##        logging.debug("Leaving on_networkwindow_raised()")

    @Slot("")
    def on_actionNew_triggered(self):
        """
        This is a slot. It's automatically connected to the actionNew
        created in the QtDesigner.
        """
        self.new_model()

    @Slot("")
    def on_actionOpen_triggered(self):
        """
        This is a slot. It's automatically connected to the actionOpen
        created in the QtDesigner.
        """
        homeDir = filehelpers.getHomeDir()

        filenameTuple = QFileDialog.getOpenFileName(
            parent=self,
            directory=homeDir,
            filter="SBML files (*.sbml *.xml)",
            caption="Open SBML file...")

        if filenameTuple and filenameTuple[
                0]:  # if user presses cancel, the tuple exists but is two empty unicode strings.
            filename = filenameTuple[0]
            self.load_model(filename)
        else:
            logging.info("No file selected. Didn't load anything.")

    @Slot("")
    def on_actionClose_Model_triggered(self):
        #        self.on_modelClosed(self.ActiveModelController)
        self.modelClosed.emit(self.ActiveModelController)

    @Slot("")
    def on_actionSave_triggered(self):
        """
        This is a slot. It's automatically connected to the actionSave
        created in the QtDesigner.
        """
        self.saveActiveNetwork(filename=None)

    @Slot("")
    def on_actionSave_as_triggered(self):
        """
        This is a slot. It's automatically connected to the actionSaveAs
        created in the QtDesigner.
        """
        if not self.ActiveModelController:
            logging.info("Can't save anything. No model loaded.")
            return
        filenameTuple = QFileDialog.getSaveFileName(
            parent=self,
            dir=self.ActiveModelController.filename,
            caption="Save as...",
            filter="SBML file (*.sbml *.xml)")
        if filenameTuple:
            self.saveActiveNetwork(filenameTuple[0])

    def saveActiveNetwork(self, filename=None):
        """
        Tell the currently active network controller to
        save to a file.

        @param filename: Filename of the network.
        @type filename: str
        """
        if self.ActiveModelController is None:
            logging.warning("No model loaded. Can't save anything.")
            return
        self.ActiveModelController.save(filename=filename)

    @Slot("")
    def on_actionShow_Data_Manager_triggered(self):
        """
        This is a slot. It's automatically connected to the actionShowDataManager
        created in the QtDesigner.
        """
        self.DataManagementController.show()

    @Slot("")
    def on_actionODEGenerator_triggered(self):
        """
        Open the ODE Generator information dialog.
        """
        if self.ActiveModelController and self.ActiveModelController.sbmlModel:
            self.odeViewer = ODEViewer(self,
                                       self.ActiveModelController.sbmlModel)
            self.odeViewer.show()
        else:
            logging.info("ODEs can't be shown. No model selected.")

    def closeEvent(self, event):
        """
        Override the close event to handle file saving.
        """
        if self.okToContinue():  # files will be saved in self.okToContinue()
            settings = QSettings()
            settings.setValue("Geometry", self.saveGeometry())
            settings.setValue("MainWindow/State", self.saveState())
            settings.setValue("RecentFiles", self.recentFiles)

            event.accept()
        else:
            event.ignore()

    def okToContinue(self):
        """
        Checks if it is ok to close the application.
        The user will be prompted to save files.

        @return: True, if it is ok to continue (e.g. close the app); False, otherwise
        @rtype: bool

        @todo: Make a smart save dialog to allow the user to save only certain files.
        """
        dirtyFilenames = []
        for filename, networkController in self.ModelControllers.items():
            if networkController.Dirty:
                dirtyFilenames.append(
                    networkController.filename
                )  # we don't use the filename key because it might be outdated
        if len(dirtyFilenames) == 0:  #nothing to save
            return True

        reply = QMessageBox.question(
            self,
            "BioParkin - Unsaved Changes",
            "Unsaved changes in these files:\n\n%s\n\nDo you want to save them?"
            % "\n".join(dirtyFilenames),
            buttons=QMessageBox.SaveAll | QMessageBox.Discard
            | QMessageBox.Cancel)
        if reply == QMessageBox.Cancel:
            return False
        elif reply == QMessageBox.SaveAll:
            for networkController in self.ModelControllers:
                if networkController.Dirty:
                    networkController.save()
        return True

    ############ SLOTS for SimulationWorkbenchWidget ##############

    @Slot("")
    def on_actionSimulate_triggered(self):
        self.SimulationWorkbenchController.actionSimulate.trigger()

    @Slot("")
    def on_actionComputeSensitivityOverview_triggered(self):
        self.SimulationWorkbenchController.actionComputeSensitivityOverview.trigger(
        )

    @Slot("")
    def on_actionCompute_Detailed_Sensitivities_triggered(self):
        self.SimulationWorkbenchController.actionCompute_Detailed_Sensitivities.trigger(
        )

    @Slot("")
    def on_actionEstimateParameterValues_triggered(self):
        self.SimulationWorkbenchController.actionEstimateParameterValues.trigger(
        )

    @Slot("")
    def on_actionAbout_triggered(self):
        self.aboutDialog = AboutDialog(self)
        self.aboutDialog.show()

    @Slot("")
    def on_actionShow_Results_Window_triggered(self):
        if self.SimulationWorkbenchController and self.SimulationWorkbenchController.resultsWindow:
            self.SimulationWorkbenchController.resultsWindow.show()
        else:
            logging.info(
                "Cannot show Results Window. Nothing has been simulated, yet.")
Beispiel #13
0
class AbstractViewController(QWidget):
    """
    Provides a base class for the individual data views (plot/table/sensitiviy table).
    Each of the views can have its own UI. This class here is just a set of common methods.
    """

    def __init__(self, parent):
        super(AbstractViewController, self).__init__(parent)

    def _initialize(self):
        self.dataService = DataService()
        self.experimentalData = None
        self.simulationData = None
        self.dataSourceTableModel = None
        self.dataSourceIDs = []
        self.allData = None
        self.dataSources = None

    def updateDataSources(self, dataSources, dataID=None):
        """

        Gets the data files that were produced by the last integration run
        and invokes updating the data source table and the data tabs (plot/table).

        The data structure for the data model is a dict:
        {'source ID': [list of data IDs, e.g. GnrH, ...]}
        """
        self.dataSources = dataSources
        if not self.dataSources:
            logging.info("No data sources, nothing to be shown.")
            return
            
        logging.info("Updating data sources...")

        self.dataSourceIDs = []

        if type(self.dataSources) is list:
            try:
                combinedDataSource = OrderedDict()
                for source in self.dataSources:
                    for key, value in source.items():
                        if not value.isSelected():
                            continue
                        origin = value.getId()
                        if not origin in self.dataSourceIDs:
                            self.dataSourceIDs.append(origin)

                        if key in combinedDataSource:
                            logging.debug("AbstractViewController: Duplicate key encountered while merging data sources for display.")
                        combinedDataSource[key] = value
                self.dataSources = combinedDataSource
            except:
                logging.error("AbstractViewController: Could not combine several datasource dictionaries into one.")

        if dataID:
            singledataSource = OrderedDict()
            singledataSource[dataID] = self.dataSources[dataID]
            self.dataSources = singledataSource

        if self.dataSourceTableModel:
            self.dataSourceTableModel.dataChanged.disconnect(self.on_dataSourcesChanged)

        self.dataSourceTableModel = DataSourcesTableModel(self.dataSources)
        self.dataSourceTableView.setModel(self.dataSourceTableModel)

        # use header with checkboxes
        selectableTableHeaderHorizontal = SelectableTableHeader(Qt.Horizontal, self.dataSourceTableView)
        selectableTableHeaderHorizontal.setNonSelectableIndexes([0])
        selectableTableHeaderHorizontal.sectionSelectionChanged.connect(self.on_columnSelectionChanged)
#        selectableTableHeaderHorizontal.connectSelectionModel(self.dataSourceTableModel)
        self.dataSourceTableView.setHorizontalHeader(selectableTableHeaderHorizontal)

        selectableTableHeaderVertical = SelectableTableHeader(Qt.Vertical, self.dataSourceTableView)
        selectableTableHeaderVertical.sectionSelectionChanged.connect(self.on_rowSelectionChanged)
#        selectableTableHeaderVertical.connectSelectionModel(self.dataSourceTableModel)
        self.dataSourceTableView.setVerticalHeader(selectableTableHeaderVertical)

        self.dataSourceTableView.resizeColumnsToContents()

        self.dataSourceTableModel.dataChanged.connect(self.on_dataSourcesChanged)

        self.on_dataSourcesChanged(None, None)


    def on_dataSourcesChanged(self, upperLeftIndex, lowerRightIndex):
        # for now, we disregard lowerRightIndex
        self._updateDataView() # update everything

    def getNumberOfDataItems(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getNumberOfDataItems()

    def getEntityIDs(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getEntityIDs()



    def getSourceIDs(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getSourceIDs()

    def getSelectedCombinations(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getSelectedCombinations()

    def hasData(self, dataSet):
        if not self.dataSources:
            return False
        return True if dataSet in self.dataSources.values() else False


    def _updateDataView(self):
        if not self.dataSourceTableModel:
            return
        
        selectedData = self._getSelectedData()
        if not selectedData:
            logging.info("No data, nothing to be shown.")
            self._clearView()
            return

        self._updateView(selectedData)


    def _getSelectedData(self):
        """
        Returns an ordered dictionary view of the selected data
        items - the returned dictionary is a key-based sorted version
        of all data entries
        """
        if not self.allData:    # only get actual data the first time
            self.allData = OrderedDict()
            allData = self.dataService.get_all_data()
            # 23.07.12 td:
            # do a deep copy here; in order to get the different abstract views independent of each other!
            for key in allData.keys():
                self.allData[key] = allData[key]
            
        selectedIDs = self.dataSourceTableModel.getSelectedIDs() # this returns a dict {ID: ("Simulation", "filename1", ...)}
        selectedData = {}
        for i, (selectedID, sources) in enumerate(selectedIDs.items()):
            for source in sources:
                if not self.allData.has_key(source):
                    continue
                dataOfSource = self.allData[source]
                dataOfID = dataOfSource.getData(selectedID)
                if not dataOfID:
                    continue
                if selectedID in selectedData:
                    selectedData[selectedID].append(dataOfID)
                else:
                    selectedData[selectedID] = [dataOfID]

        return selectedData#OrderedDict(sorted(selectedData.items(), key=lambda t:t[0]))


    def _updateView(self, data):
        """
        Needs to be overridden.

        Should update the data view (plot, table, ...).
        """
        logging.debug("The _updateView method has not been overridden.")

    def _clearView(self):
        """
        Needs to be overridden.

        Should clear the data view (plot, table, ...).
        """
        logging.debug("The _clearView method has not been overridden.")

    def _selectAllSources(self, doSelect, column=None, row=None):
        if self.dataSourceTableModel:
            self.dataSourceTableModel.selectAllSources(doSelect, column, row)


    def _invertSourceSelection(self):
        if self.dataSourceTableModel:
            self.dataSourceTableModel.invertSelection()


    @Slot("")
    def on_actionSave_triggered(self):
        """
        Needs to be overriden.

        Should show a dialog to save the currently shown data (table, plot, ...).
        """
        logging.debug("The on_actionSave_triggered method has not been overridden.")


    @Slot("")
    def on_actionSelectAll_triggered(self):
        """
        Selects all sources.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._selectAllSources(True)

    @Slot("")
    def on_actionDeselectAll_triggered(self):
        """
        Deselects all sources.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._selectAllSources(False)

    @Slot("")
    def on_actionInvertSelection_triggered(self):
        """
        Inverts the current source selection.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._invertSourceSelection()

    def on_columnSelectionChanged(self, index, selectionState):
        if selectionState == Qt.Checked:
            selected = True
        elif selectionState == Qt.Unchecked:
            selected = False
        else:   # selection is Qt.PartiallyChecked -> no update of selections here
            return
        self._selectAllSources(selected, column=index)

    def on_rowSelectionChanged(self, index, selectionState):
        if selectionState == Qt.Checked:
            selected = True
        elif selectionState == Qt.Unchecked:
            selected = False
        else:   # selection is Qt.PartiallyChecked -> no update of selections here
            return
        self._selectAllSources(selected, row=index)
class DataImportWidget(QWidget, Ui_DataImportWidget):
    """
    This is a very simple widget that provides some buttons
    to load experimental data.

    @since: 2011-08-24
    """
    __author__ = "Moritz Wade"
    __contact__ = "*****@*****.**"
    __copyright__ = "Zuse Institute Berlin 2011"

    updatedDataEvent = Signal(OrderedDict)

    def __init__(self, parent, parkinController):
        super(DataImportWidget, self).__init__(parent)
        self.setupUi(self)

        self.currentExpDataFilename = None
        self.dataService = DataService()
        self.parkinController = parkinController

    def browseExpData(self):
        """
        Shows a file open dialog.
        """

        homeDir = filehelpers.getHomeDir()
        openDir = self.currentExpDataFilename if self.currentExpDataFilename else homeDir
        filenameTuple = QFileDialog.getOpenFileName(
            parent=self,
            caption="Browse for data file...",
            directory=openDir,
            filter=
            "BioPARKIN CSV data file (*.csv *.txt);;Legacy PARKIN data file (*.dat);;All filetypes (*.*"
        )

        self.setCurrentExpDataDirectory(filenameTuple[0])

    def setCurrentExpDataDirectory(self, filename):
        self.currentExpDataFilename = filename
        self.lineEdit.setText(self.currentExpDataFilename)

    def updateExpData(self, readFile=False):
        if self.dataService.has_data(
                self.currentExpDataFilename
        ):  # don't load the same data twice (remove the data first, if you want to reload)
            logging.info("This data file is already loaded: %s" %
                         self.currentExpDataFilename)
            return

        if readFile:
            self.currentExpDataFilename = self.lineEdit.text()
            format = self.getExpDataFileFormat()

            self.dataService.load_data([self.currentExpDataFilename],
                                       type=services.dataservice.EXPERIMENTAL,
                                       parkinController=self.parkinController,
                                       format=format)

        expData = self.dataService.get_experimental_data()
        if expData:
            self.updatedDataEvent.emit(expData)

    def getExpDataFileFormat(self):
        filename = self.currentExpDataFilename
        if filename.endswith("csv") or filename.endswith("txt"):
            format = datamanagement.dataset.FORMAT_EXP_SIMPLE_CSV
        elif filename.endswith("dat"):
            format = datamanagement.dataset.FORMAT_EXP_PARKIN
        else:
            format = None

        return format

    ###### SLOTS #######

    @Slot("")
    def on_buttonBrowse_clicked(self):
        #logging.debug("SimulationWorkbenchController: in on_buttonBrowseExpData_clicked()")
        self.browseExpData()
        if not self.currentExpDataFilename:
            logging.info("No file selected. Can't import data.")
            return
        self.updateExpData(readFile=True)
        self.lineEdit.clear()

    @Slot("")
    def on_buttonImport_clicked(self):
        if not self.currentExpDataFilename:
            logging.info("No filename given. Can't import data.")
            return
        #logging.debug("SimulationWorkbenchController: in on_buttonBrowseExpData_clicked()")
        self.updateExpData(readFile=True)
        self.lineEdit.clear()
Beispiel #15
0
class DataBrowser(QWidget, Ui_DataBrowser):
    """
    @since: 2011-08-24
    """
    __author__ = "Moritz Wade"
    __contact__ = "*****@*****.**"
    __copyright__ = "Zuse Institute Berlin 2011"

    def __init__(self, parent, id, dataSet):
        super(DataBrowser, self).__init__(parent)
        self.setupUi(self)

        self._simWorkbench = None
        self.dataService = None

        self.id = id
        self.data = dataSet

        self.optionsService = OptionsService()

        # create the custom selectable table header
        self.selectableHeader = SelectableTableHeader(Qt.Horizontal,
                                                      self.tableView)
        self.selectableHeader.setNonSelectableIndexes([0])
        self.selectableHeader.sectionSelectionChanged.connect(
            self.on_columnSelectionChanged)

        self.tableView.setHorizontalHeader(self.selectableHeader)

        # create the data model
        self.dataModel = DataBrowserModel(self, self.id, self.data)
        self.tableView.setModel(self.dataModel)

        self._setUpSelectionCheckBox()
        self._updateInfoPane()

        if not self.optionsService.getDebug():
            self.groupBoxPerturbation.setVisible(False)

    def getId(self):
        return self.id

    def setSimulationWorkbench(self, simWorkbench):
        self._simWorkbench = simWorkbench

    def getSelectionCheckBox(self):
        return self._selectionCheckBox

    def isSelected(self):
        checkState = self._selectionCheckBox.checkState()
        return True if checkState == Qt.Checked else False

    def _setUpSelectionCheckBox(self):
        self._selectionCheckBox = QCheckBox()
        self._selectionCheckBox.setChecked(True)
        infoText = "Select or deselect this data (e.g. to be included in plots and computations)."
        self._selectionCheckBox.setStatusTip(infoText)
        self._selectionCheckBox.setToolTip(infoText)

        self._selectionCheckBox.stateChanged.connect(self._selectionChanged)

    def _updateInfoPane(self):
        """
        Updates the info pane with basic info about the loaded data
        and the data file (if any).
        """
        self.lineEditInfoSpecies.setText(str(self.data.getNumOfRealData()))
        self.lineEditInfoDataType.setText(self.data.type)

        #        self.lineEditInfoFormat.setText(self.data.format)

        filepath = self.data.filename
        if filepath and os.path.exists(filepath):
            self.lineEditInfoPath.setText(filepath)

            filesize = os.path.getsize(filepath)
            filesize = filesize / 1024  # displaying kB
            self.lineEditInfoFilesize.setText("%s kB" % filesize)

            timeLastModifiedEpoch = os.path.getmtime(filepath)
            timeLastModified = time.strftime(
                "%a, %d %b %Y %H:%M:%S", time.localtime(timeLastModifiedEpoch))
            self.lineEditInfoLastModified.setText(str(timeLastModified))
        else:
            noFileText = "No File"
            self.lineEditInfoPath.setText(noFileText)
            self.lineEditInfoFilesize.setText(noFileText)
            self.lineEditInfoLastModified.setText(noFileText)

    def remove(self):
        """
        Cleans up stuff then destroys self.

        It's not sure whether this is really needed
        but it might serve to close some memory holes
        (e.g. dangling references somewhere).
        """
        del self.dataModel
        del self

    @Slot()
    def on_actionPlot_triggered(self):
        dataDict = {self.data.getId(): self.data}
        self._simWorkbench.plotExpData(dataDict)

    @Slot()
    def on_buttonPerturb_clicked(self):
        """
        Perturbs the data by the % given
        in self.spinBoxPerturb.
        """
        percentage = self.spinBoxPerturb.value()
        factor = percentage / 100.0

        for entity, entityData in self.data.getData().items():
            if not entityData.isSelected():
                continue
            id = entity.getId() if type(entity) == EntityData else str(entity)
            logging.debug("Perturbing data of EntityData: %s" % id)
            for i in xrange(len(entityData.datapoints)):
                value = entityData.datapoints[i]
                if not value:  # for None values
                    continue
                fraction = value * factor  # fraction of value that will be added or substracted
                #newValue = value + random.uniform(-1 * fraction, fraction)
                newValue = value + random.uniform(-1, 1) * fraction
                #                    newValue = value - fraction if random.random() < 0.5 else value + fraction
                entityData.setDatapoint(i, newValue)

    @Slot("")
    def on_buttonSaveAs_clicked(self):
        logging.debug("Saving data. Displaying file chooser...")
        file_choices = "Tab-Delimited Text File *.txt (*.txt)"

        path = unicode(
            QFileDialog.getSaveFileName(self, 'Save file', '',
                                        file_choices)[0])

        if not path.endswith(".txt"):
            path += ".txt"

        if path:
            if not self.dataService:
                self.dataService = DataService()

            id = self.data.getId()
            self.dataService.save_data_as_csv(id, path)
            logging.info("Saved data to %s" % path)

    @Slot()
    def on_buttonTimeshift_clicked(self):
        """
        Timeshift data within this DataBrowser (i.e. DataSet).
        Not only shift the global timepoints but also the timepoint lists
        within the individiual EntityData objects.
        """
        try:
            shiftValue = float(self.lineEditTimeshift.text())
            self.dataModel.doTimeshift(shiftValue)
        except Exception, e:
            logging.error(
                "DataBrowser.on_buttonTimeshift_clicked(): Error while timeshifting the data: %s"
                % e)
Beispiel #16
0
class BioParkinController(QMainWindow, Ui_MainWindow):
    """
    This is the heart of BioParkin. It sets up the general UI
    (MainWindow, some Views, ...), handles creation and management of
    individual network windows, and instantiates needed services
    (for easy access to data, status bar, ...).

    This class inherits from QMainWindow for its functionality and from
    the (automatically generated) Ui_MainWindow for the design of the UI
    (including the self.setupUi() method).

    @param parent: The standard Qt parent.
    @type parent: QWidget

    @organization: Zuse Insitute Berlin
    """

    __version__ = "1.2.27"
    __author__ = "Moritz Wade & Thomas Dierkes"
    __contact__ = "[email protected] or [email protected]"
    __copyright__ = "Zuse Institute Berlin 2011"

    newNetworkWindowCreated = Signal()
    networkWindowRaised = Signal()
    activeModelChanged = Signal(ModelController)
    modelClosed = Signal(ModelController)

    def __init__(self, args, parent=None):
        """
        This initialization does a lot of stuff. :)

        * State variables are set up
        * Views are created and tied to UI parts (e.g. Docks)
        * Logging is set up
        * Services (StatusBar, Data, ...) are started
        * Necessary slots are connected

        """
        super(BioParkinController, self).__init__(parent)

        # for locale testing
        # locale.setlocale(locale.LC_ALL, 'de_DE')
        #        locale.setlocale(locale.LC_ALL, 'deu_deu')

        self.startTime = time.localtime()

        # set file logger
        self.rotatingFileHandler = logging.handlers.RotatingFileHandler(_LOG_FILENAME, maxBytes=1000000, backupCount=5)
        self.rotatingFileHandler.setFormatter(logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
        self.logger = logging.getLogger()  # gets root logger
        self.logger.addHandler(self.rotatingFileHandler)

        # Status bar logger
        self.statusBarLoggingHandler = StatusBarLoggingHandler()
        self.statusBarLoggingHandler.setLevel(logging.INFO)  # only log on info level
        self.logger.addHandler(self.statusBarLoggingHandler)

        # parse command line arguments
        parser = OptionParser()
        parser.add_option(
            "-d",
            "--debug",
            action="store_true",
            dest=OPTION_DEBUG,
            default=False,
            help="Include debugging information in console and file log",
        )
        self.options, args = parser.parse_args()

        self.optionsService = OptionsService()
        self.optionsService.setDebug(self.options.debug)

        # set logging options
        if self.options.debug:
            self.logger.setLevel(logging.DEBUG)
            self.rotatingFileHandler.setLevel(logging.DEBUG)
            logging.info("Debug logging active.")
        else:
            self.logger.setLevel(logging.INFO)
            self.rotatingFileHandler.setLevel(logging.INFO)
            logging.info("Debug logging not active.")

        logging.info("Starting BioPARKIN... %s" % self.startTime)

        ##### LOGGING #####
        logging.info("BioPARKIN started (version %s)" % BioParkinController.__version__)
        logging.info("Command line arguments: %s" % args)
        logging.info("Python version: %s" % sys.version)
        logging.info("PySide version: %s" % PySide.__version__)
        logging.info("PARKINcpp version: %s" % PARKINCPP_DOTTED_VERSION)
        logging.info("libSBML version: %s" % LIBSBML_DOTTED_VERSION)
        logging.info("Matplotlib version: %s" % matplotlib.__version__)
        #        logging.info("NetworkX version: %s" % networkx.__version__)
        logging.info("Python Image Library version: %s" % Image.VERSION)

        self.setupUi(self)
        self._mdiArea.hide()
        self.setWindowTitle("BioPARKIN v%s" % BioParkinController.__version__)

        # restore previous settings
        settings = QSettings()
        try:
            self.recentFiles = settings.value("RecentFiles", [])

            # handles the case if only one file is in the "list" in Linux (it's retrieved as unicode string in this case)
            if type(self.recentFiles) is str or type(self.recentFiles) is unicode:
                self.recentFiles = [self.recentFiles]

            logging.info("Recently opened files: %s" % self.recentFiles)
        except:
            logging.warning("Can't access list of recently opened files. Resetting the list.")
            self.recentFiles = []

        self.updateFileMenu()
        self.aboutDialog = None

        geometry = settings.value("Geometry")
        if geometry:
            self.restoreGeometry(geometry)

        state = settings.value("MainWindow/State")
        if state:
            self.restoreState(state)

        self.ModelControllers = {}
        #        self.SubWindowToModelControllers = {}
        #        self.NetworkWindowCount = 0
        #        self.ActiveNetworkWindow = None
        self.ActiveModelController = None
        #        self.networkSubWindows = {}

        self.integrator = None
        self.odeViewer = None

        self.ModelView = ModelView(self.masterDetailSplitter, self)
        self.ModelTreeView = SBMLEntityWidget(self.masterDetailSplitter)
        self.EntityTableView = EntityTableView(self.masterDetailSplitter)

        self.mainWindowViews = [self.ModelTreeView, self.EntityTableView]  # used to iterate over Views

        # set up Data Service and Data Viewer
        datahandling.parkinController = self
        self.dataService = DataService()

        # debugging#############
        BASE_PATH = reduce(
            lambda l, r: l + os.path.sep + r, os.path.dirname(os.path.realpath(__file__)).split(os.path.sep)[:-1]
        )

        # add ../../templates (relative to the file (!) and not to the CWD)
        dataPath = os.path.join(BASE_PATH, "data")
        #######################

        self.SimulationWorkbenchController = SimulationWorkbenchController(parent=None, parkinController=self)
        self.mainTabWidget.addTab(self.SimulationWorkbenchController, "Workbench")

        # hook up status bar with progress service (that threads can connect to)
        self.statusBarService = StatusBarService(
            self.statusBar()
        )  # first time, service is instantiated => give statusBar reference!
        self.progressBarService = ProgressBarService(self, self.statusBarService)

        self.statusBarLoggingHandler.setStatusBar(self.statusBarService)

        self.warningsService = WarningService.getInstance()
        self.warningsDialog = WarningsDialog(self, self.actionShow_Warnings, self.warningsService)

        # register signals
        self.activeModelChanged.connect(self.on_activeModelChanged)
        self.modelClosed.connect(self.on_modelClosed)
        self.menuFile.aboutToShow.connect(self.updateFileMenu)

        # for debugging
        self.dummyThread = None

        try:  # try to set correct taskbar icon in Windows 7
            myappid = "ZIB.BioPARKIN"  # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        except:
            pass

    def updateFileMenu(self):
        """
        Updates the file menu dynamically, so that recent files can be shown.
        """
        self.menuFile.clear()
        #        self.menuFile.addAction(self.actionNew)    # disable for now
        self.menuFile.addAction(self.actionOpen)
        self.menuFile.addAction(self.actionSave)
        self.menuFile.addAction(self.actionSave_as)
        self.menuFile.addAction(self.actionClose_Model)

        recentFiles = []
        for filename in self.recentFiles:
            if QFile.exists(filename):
                recentFiles.append(filename)

        if len(self.recentFiles) > 0:
            self.menuFile.addSeparator()
            for i, filename in enumerate(recentFiles):
                action = QAction("&%d %s" % (i + 1, QFileInfo(filename).fileName()), self)
                action.setData(filename)
                action.setStatusTip("Opens recent file %s" % QFileInfo(filename).fileName())
                action.setShortcut(QKeySequence(Qt.CTRL | (Qt.Key_1 + i)))
                action.triggered.connect(self.load_model)
                self.menuFile.addAction(action)

        self.menuFile.addSeparator()
        self.menuFile.addAction(self.actionQuit)

    def new_model(self):
        """
        Not yet supported.
        """
        pass

    def load_model(self, filename=None):
        """
        Loads a given SBML file, thereby creating a new subwindow
        on the main MDI Area.
        If filename is None, it creates a new model.

        There are a lot of reference variables, so that the system knows the
        currently active subwindow, etc.

        @param filename: The filename of the model. If None, a new model is created.
        @type filename: str
        """
        if not filename:
            action = self.sender()
            if type(action) == QAction:
                filename = action.data()
            else:
                return

        # note: this has been (temporarily added) to allow only one file to be open at the same time
        # We will probably change this behaviour again later, once we have decided how to handle
        # multiple-model results, etc. intelligently
        if len(self.ModelControllers) > 0:

            # show warning dialog
            msgBox = QMessageBox()
            infoText = """<b>Another model is currently loaded.</b><br>
            """
            msgBox.setText(infoText)
            infoTextShort = "Do you want to save the current model (you will be prompted to enter a new filename)?"
            msgBox.setInformativeText(infoTextShort)
            msgBox.setWindowTitle(infoTextShort)
            msgBox.setStandardButtons(QMessageBox.Save | QMessageBox.Discard)
            msgBox.setDefaultButton(QMessageBox.Save)
            msgBox.setIcon(QMessageBox.Warning)
            clickedButton = msgBox.exec_()

            if clickedButton == QMessageBox.Save:
                self.actionSave_as.trigger()

            for (
                modelController
            ) in self.ModelControllers.values():  # close all models (in theory, there should be only one :)
                self.modelClosed.emit(modelController)

        #        self.NetworkWindowCount += 1
        #        self.setStatusTip("Opening file %s..." % filename)
        self.statusBar().showMessage("Opening file %s..." % filename, 2000)
        modelController = ModelController(filename=filename, views=self.mainWindowViews)

        #        # create NetworkViewController
        #        networkViewController = NetworkViewController(modelController=modelController)
        #        networkView = networkViewController.createNetworkView(self) # sets networkController.networkView internally
        #        networkView.setMinimumSize(400, 300)
        #        modelController.setViews(networkViewController=networkViewController)

        #        # Create Subwindow to hold the NetworkView
        #        subWindow = QMdiSubWindow(parent=self._mdiArea)
        #        networkViewController.subWindow = subWindow
        #        subWindow.setAttribute(Qt.WA_DeleteOnClose)
        #        subWindow.setWidget(networkView)
        #        subWindow.setOption(QMdiSubWindow.RubberBandResize, True)
        #        self._mdiArea.addSubWindow(subWindow)
        #        subWindow.activateWindow()
        #        subWindow.show()    # important!
        #        networkView.show()

        # handle references
        filename = modelController.filename
        #        self.SubWindowToModelControllers[subWindow] = modelController
        #        self.networkSubWindows[modelController] = subWindow #networkView
        self.ModelControllers[filename] = modelController
        #        self.ActiveNetworkWindow = networkWindow
        self.ActiveModelController = modelController

        #        self.connectNetworkWindowSignals(networkView, subWindow)

        # emit custom Signal so that e.g. Simulationworkbench are notified of the new subwindow
        #        self.newNetworkWindowCreated.emit()
        self.activeModelChanged.emit(modelController)

        # handle recent files list
        if filename in self.recentFiles:
            self.recentFiles.remove(filename)
        self.recentFiles.insert(0, filename)
        if len(self.recentFiles) > NUM_RECENT_FILES:  # cap list at length of NUM_RECENT_FILES
            self.recentFiles = self.recentFiles[:NUM_RECENT_FILES]

    #    def getMdiArea(self):
    #        return self._mdiArea

    #    @Slot("QWidget")
    #    def connectNetworkWindowSignals(self, networkWindow, subWindow):
    #        """
    #        Connect the signals of network windows (e.g. network is about to be destroyed, etc.)
    #
    #        @param networkWindow: A network view
    #        @type networkWindow: NetworkView
    #
    #        @param subWindow: A Qt QMdiArea sub window
    #        @type subWindow: QMdiSubWindow
    #        """
    #        #self.connect(button3, SIGNAL("clicked()"),    lambda who="Three": self.anyButton(who))
    #
    #        self.connect(networkWindow, SIGNAL("destroyed()"),
    #                     lambda who=networkWindow: self.on_networkwindow_destroyed(who))

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat("Filename"):
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        """
        Handles the drop event if the user "drops" a file somewhere within BioPARKIN's window.
        """
        # get filename
        uris = event.mimeData().urls()  # support opening several models at once

        # note: uncomment this, to enable drag'n'dropping of multiple models again
        #        for uri in uris:
        #            filename = uri.toLocalFile()
        #            #open file
        #            self.load_model(filename)
        filename = uris[0].toLocalFile()
        self.load_model(filename)
        if len(uris) > 1:
            logging.info(
                "You dragged more than one model to BioPARKIN. Currently, only one model is supported to be opened at the same time. Only the first dragged model was loaded."
            )

    def on_modelClosed(self, modelController):
        """
        Whenever the Signal self.modelClosed is emitted, this
        method is called.
        It removes the modelController of the closed model from
        the management dictionary and updates all local Views.
        """
        if not modelController:
            logging.info("Can't close the model. No model selected.")

            #### abusing this place for testing ####
            #            self.dummyThread = DummyProgressThread()
            #            self.progressBarService.connect_to_thread(self.dummyThread)
            #            self.dummyThread.start()

            #            self.dummyThread = DummyThrobberThread()
            #            self.progressBarService.connect_to_thread(self.dummyThread)
            #            self.dummyThread.start()

            ########################################

            return
        if self.ModelControllers.has_key(
            modelController.filename
        ):  # we do this to remove the model controller from the management dict
            self.ModelControllers.pop(modelController.filename)

        if len(self.ModelControllers) == 0:
            # 26.07.12 td: the next line has been commented out
            self.dataService.remove_all_simulated_data()
            self.ActiveModelController = None
            for view in self.mainWindowViews:
                view.setModel(None)

    #    def on_networkwindow_destroyed(self, networkWindow):
    #        """
    #        This is a slot. It's called to clean things up when a network
    #        window is destroyed. Basically, it just gets the correct ModelController
    #        and passes it on using the modelClosed signal of the BioPARKIN controller.
    #
    #        @param networkWindow: A network view
    #        @type networkWindow: NetworkView
    #        """
    #        logging.debug("Destroying a NetworkWindow: %s" % networkWindow)
    #        modelController = networkWindow.controller.modelController
    #        self.modelClosed.emit(modelController)
    #
    #    def closeNetworkWindow(self, modelController):
    #        if self.networkSubWindows.has_key(modelController): # might have been removed already
    #            self.networkSubWindows.pop(modelController).close() #removes window from dict and closes it

    def on_activeModelChanged(self, activeModelController):
        """
        Whenever the active model changes, the appropriate Signal
        self.activeModelChanged should be emitted. When that is done, this method
        is called.
        """
        logging.info("Active Model: %s" % activeModelController.filename)
        if activeModelController is not None:
            self.ActiveModelController = activeModelController
            for view in self.mainWindowViews:
                view.setModel(self.ActiveModelController.proxyModel, mainModel=self.ActiveModelController.sbmlModel)
                view.setSelectionModel(self.ActiveModelController.selectionModel)

    #    def selectNetworkView(self, modelController):
    #        subwindow = self.networkSubWindows[modelController]
    ##        subwindow.show()
    #        subwindow.raise_()
    #        subwindow.activateWindow()
    ##        subwindow.setFocus()

    #    def on_networkwindow_raised(self, subWindow):
    #        """
    #        This is a slot. It's called when a network window gets focus.
    #        Some references have to be set, and most importantly, all the Views
    #        have to be switched so that they use the data model behind the
    #        newly focused network window.
    #
    #        @param subWindow: A sub window
    #        @type subWindow: QMdiSubWindow
    #        """
    #        if subWindow is None:
    #            return
    #        if not self.SubWindowToModelControllers.has_key(subWindow):
    #            return
    #
    #        activeModelController = self.SubWindowToModelControllers[subWindow]
    ##        self.ActiveNetworkWindow = self.ActiveModelController.getNetworkView()
    #
    ##        self.on_activeModelChanged()
    #        self.activeModelChanged.emit(activeModelController)
    ##        self.networkWindowRaised.emit()
    #
    ##        logging.debug("Leaving on_networkwindow_raised()")

    @Slot("")
    def on_actionNew_triggered(self):
        """
        This is a slot. It's automatically connected to the actionNew
        created in the QtDesigner.
        """
        self.new_model()

    @Slot("")
    def on_actionOpen_triggered(self):
        """
        This is a slot. It's automatically connected to the actionOpen
        created in the QtDesigner.
        """
        homeDir = filehelpers.getHomeDir()

        filenameTuple = QFileDialog.getOpenFileName(
            parent=self, directory=homeDir, filter="SBML files (*.sbml *.xml)", caption="Open SBML file..."
        )

        if (
            filenameTuple and filenameTuple[0]
        ):  # if user presses cancel, the tuple exists but is two empty unicode strings.
            filename = filenameTuple[0]
            self.load_model(filename)
        else:
            logging.info("No file selected. Didn't load anything.")

    @Slot("")
    def on_actionClose_Model_triggered(self):
        #        self.on_modelClosed(self.ActiveModelController)
        self.modelClosed.emit(self.ActiveModelController)

    @Slot("")
    def on_actionSave_triggered(self):
        """
        This is a slot. It's automatically connected to the actionSave
        created in the QtDesigner.
        """
        self.saveActiveNetwork(filename=None)

    @Slot("")
    def on_actionSave_as_triggered(self):
        """
        This is a slot. It's automatically connected to the actionSaveAs
        created in the QtDesigner.
        """
        if not self.ActiveModelController:
            logging.info("Can't save anything. No model loaded.")
            return
        filenameTuple = QFileDialog.getSaveFileName(
            parent=self,
            dir=self.ActiveModelController.filename,
            caption="Save as...",
            filter="SBML file (*.sbml *.xml)",
        )
        if filenameTuple:
            self.saveActiveNetwork(filenameTuple[0])

    def saveActiveNetwork(self, filename=None):
        """
        Tell the currently active network controller to
        save to a file.

        @param filename: Filename of the network.
        @type filename: str
        """
        if self.ActiveModelController is None:
            logging.warning("No model loaded. Can't save anything.")
            return
        self.ActiveModelController.save(filename=filename)

    @Slot("")
    def on_actionShow_Data_Manager_triggered(self):
        """
        This is a slot. It's automatically connected to the actionShowDataManager
        created in the QtDesigner.
        """
        self.DataManagementController.show()

    @Slot("")
    def on_actionODEGenerator_triggered(self):
        """
        Open the ODE Generator information dialog.
        """
        if self.ActiveModelController and self.ActiveModelController.sbmlModel:
            self.odeViewer = ODEViewer(self, self.ActiveModelController.sbmlModel)
            self.odeViewer.show()
        else:
            logging.info("ODEs can't be shown. No model selected.")

    def closeEvent(self, event):
        """
        Override the close event to handle file saving.
        """
        if self.okToContinue():  # files will be saved in self.okToContinue()
            settings = QSettings()
            settings.setValue("Geometry", self.saveGeometry())
            settings.setValue("MainWindow/State", self.saveState())
            settings.setValue("RecentFiles", self.recentFiles)

            event.accept()
        else:
            event.ignore()

    def okToContinue(self):
        """
        Checks if it is ok to close the application.
        The user will be prompted to save files.

        @return: True, if it is ok to continue (e.g. close the app); False, otherwise
        @rtype: bool

        @todo: Make a smart save dialog to allow the user to save only certain files.
        """
        dirtyFilenames = []
        for filename, networkController in self.ModelControllers.items():
            if networkController.Dirty:
                dirtyFilenames.append(
                    networkController.filename
                )  # we don't use the filename key because it might be outdated
        if len(dirtyFilenames) == 0:  # nothing to save
            return True

        reply = QMessageBox.question(
            self,
            "BioParkin - Unsaved Changes",
            "Unsaved changes in these files:\n\n%s\n\nDo you want to save them?" % "\n".join(dirtyFilenames),
            buttons=QMessageBox.SaveAll | QMessageBox.Discard | QMessageBox.Cancel,
        )
        if reply == QMessageBox.Cancel:
            return False
        elif reply == QMessageBox.SaveAll:
            for networkController in self.ModelControllers:
                if networkController.Dirty:
                    networkController.save()
        return True

    ############ SLOTS for SimulationWorkbenchWidget ##############

    @Slot("")
    def on_actionSimulate_triggered(self):
        self.SimulationWorkbenchController.actionSimulate.trigger()

    @Slot("")
    def on_actionComputeSensitivityOverview_triggered(self):
        self.SimulationWorkbenchController.actionComputeSensitivityOverview.trigger()

    @Slot("")
    def on_actionCompute_Detailed_Sensitivities_triggered(self):
        self.SimulationWorkbenchController.actionCompute_Detailed_Sensitivities.trigger()

    @Slot("")
    def on_actionEstimateParameterValues_triggered(self):
        self.SimulationWorkbenchController.actionEstimateParameterValues.trigger()

    @Slot("")
    def on_actionAbout_triggered(self):
        self.aboutDialog = AboutDialog(self)
        self.aboutDialog.show()

    @Slot("")
    def on_actionShow_Results_Window_triggered(self):
        if self.SimulationWorkbenchController and self.SimulationWorkbenchController.resultsWindow:
            self.SimulationWorkbenchController.resultsWindow.show()
        else:
            logging.info("Cannot show Results Window. Nothing has been simulated, yet.")
Beispiel #17
0
class DataImportWidget(QWidget, Ui_DataImportWidget):
    """
    This is a very simple widget that provides some buttons
    to load experimental data.

    @since: 2011-08-24
    """
    __author__ = "Moritz Wade"
    __contact__ = "*****@*****.**"
    __copyright__ = "Zuse Institute Berlin 2011"


    updatedDataEvent = Signal(OrderedDict)

    def __init__(self, parent, parkinController):
        super(DataImportWidget, self).__init__(parent)
        self.setupUi(self)
        
        self.currentExpDataFilename = None
        self.dataService = DataService()
        self.parkinController = parkinController

    def browseExpData(self):
        """
        Shows a file open dialog.
        """

        homeDir = filehelpers.getHomeDir()
        openDir = self.currentExpDataFilename if self.currentExpDataFilename else homeDir
        filenameTuple = QFileDialog.getOpenFileName(parent=self,
                                               caption="Browse for data file...",
                                               directory=openDir,
                                               filter="BioPARKIN CSV data file (*.csv *.txt);;Legacy PARKIN data file (*.dat);;All filetypes (*.*")

        self.setCurrentExpDataDirectory(filenameTuple[0])

    def setCurrentExpDataDirectory(self, filename):
        self.currentExpDataFilename = filename
        self.lineEdit.setText(self.currentExpDataFilename)

    def updateExpData(self, readFile=False):
        if self.dataService.has_data(self.currentExpDataFilename):   # don't load the same data twice (remove the data first, if you want to reload)
            logging.info("This data file is already loaded: %s" % self.currentExpDataFilename)
            return

        if readFile:
            self.currentExpDataFilename = self.lineEdit.text()
            format = self.getExpDataFileFormat()

            self.dataService.load_data([self.currentExpDataFilename], type=services.dataservice.EXPERIMENTAL,
                                       parkinController=self.parkinController, format=format)

        expData = self.dataService.get_experimental_data()
        if expData:
            self.updatedDataEvent.emit(expData)

    def getExpDataFileFormat(self):
        filename = self.currentExpDataFilename
        if filename.endswith("csv") or filename.endswith("txt"):
            format = datamanagement.dataset.FORMAT_EXP_SIMPLE_CSV
        elif filename.endswith("dat"):
            format = datamanagement.dataset.FORMAT_EXP_PARKIN
        else:
            format = None

        return format

    ###### SLOTS #######

    @Slot("")
    def on_buttonBrowse_clicked(self):
        #logging.debug("SimulationWorkbenchController: in on_buttonBrowseExpData_clicked()")
        self.browseExpData()
        if not self.currentExpDataFilename:
            logging.info("No file selected. Can't import data.")
            return
        self.updateExpData(readFile=True)
        self.lineEdit.clear()

    @Slot("")
    def on_buttonImport_clicked(self):
        if not self.currentExpDataFilename:
            logging.info("No filename given. Can't import data.")
            return
        #logging.debug("SimulationWorkbenchController: in on_buttonBrowseExpData_clicked()")
        self.updateExpData(readFile=True)
        self.lineEdit.clear()
Beispiel #18
0
    def __init__(self, parent=None):
        '''
        Creates a data model from the data (so that changes in the data
        are reflected in the View).
        
        '''
        super(DataViewingController, self).__init__(parent)
        self.setupUi(self)

        self.dataService = DataService()
        experimentalData = self.dataService.get_experimental_data()
        simulationData = self.dataService.get_simulation_data()

        #data = ordereddict()
        self.data = OrderedDict()
        if simulationData is not None and len(simulationData) > 0:
            self.simulationData = simulationData
            for (sbmlEntity, entityData) in self.simulationData.items():
                #sbmlRef = entityData.sbmlEntity
                dataTuple = (entityData, None)
                self.data[sbmlEntity] = dataTuple
        else:
            self.simulationData = None

        if experimentalData is not None:
            self.experimentalData = experimentalData
            for (sbmlEntity, entityData) in experimentalData.items():
                #sbmlRef = entityData.sbmlEntity
                if sbmlEntity in self.data:
                    dataTuple = self.data[sbmlEntity]
                    dataTuple = (dataTuple[0], entityData)
                    self.data[sbmlEntity] = dataTuple
                else:
                    dataTuple = (entityData, None)
                    self.data[sbmlEntity] = dataTuple
        else:
            self.experimentalData = None

        if self.experimentalData or self.simulationData:
            self.dataModel = SourcesTableModel(
                combinedData=self.data
                #experimentalData = self.experimentalData,
                #simulationData = self.simulationData
            )
            self.connect(self.dataModel,
                         SIGNAL("dataChanged(QModelIndex, QModelIndex)"),
                         self.update_plots)

        #self.data = []  # create single list with all data entities
#        for item in self.experimentalData:
#            self.data.append(item)
#        for item in self.simulationData:
#            if item in self.data:
#                continue
#            self.data.append(item)

        self.populate_sources_table()

        #        self.plotWindows = {}
        #        self.flatListOfPlotWidgets = []
        self.existingPlotWindows = {}
        self.update_plots()  # testing
Beispiel #19
0
    def __init__(self, args, parent=None):
        """
        This initialization does a lot of stuff. :)

        * State variables are set up
        * Views are created and tied to UI parts (e.g. Docks)
        * Logging is set up
        * Services (StatusBar, Data, ...) are started
        * Necessary slots are connected

        """
        super(BioParkinController, self).__init__(parent)

        # for locale testing
        # locale.setlocale(locale.LC_ALL, 'de_DE')
        #        locale.setlocale(locale.LC_ALL, 'deu_deu')

        self.startTime = time.localtime()

        # set file logger
        self.rotatingFileHandler = logging.handlers.RotatingFileHandler(_LOG_FILENAME, maxBytes=1000000, backupCount=5)
        self.rotatingFileHandler.setFormatter(logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
        self.logger = logging.getLogger()  # gets root logger
        self.logger.addHandler(self.rotatingFileHandler)

        # Status bar logger
        self.statusBarLoggingHandler = StatusBarLoggingHandler()
        self.statusBarLoggingHandler.setLevel(logging.INFO)  # only log on info level
        self.logger.addHandler(self.statusBarLoggingHandler)

        # parse command line arguments
        parser = OptionParser()
        parser.add_option(
            "-d",
            "--debug",
            action="store_true",
            dest=OPTION_DEBUG,
            default=False,
            help="Include debugging information in console and file log",
        )
        self.options, args = parser.parse_args()

        self.optionsService = OptionsService()
        self.optionsService.setDebug(self.options.debug)

        # set logging options
        if self.options.debug:
            self.logger.setLevel(logging.DEBUG)
            self.rotatingFileHandler.setLevel(logging.DEBUG)
            logging.info("Debug logging active.")
        else:
            self.logger.setLevel(logging.INFO)
            self.rotatingFileHandler.setLevel(logging.INFO)
            logging.info("Debug logging not active.")

        logging.info("Starting BioPARKIN... %s" % self.startTime)

        ##### LOGGING #####
        logging.info("BioPARKIN started (version %s)" % BioParkinController.__version__)
        logging.info("Command line arguments: %s" % args)
        logging.info("Python version: %s" % sys.version)
        logging.info("PySide version: %s" % PySide.__version__)
        logging.info("PARKINcpp version: %s" % PARKINCPP_DOTTED_VERSION)
        logging.info("libSBML version: %s" % LIBSBML_DOTTED_VERSION)
        logging.info("Matplotlib version: %s" % matplotlib.__version__)
        #        logging.info("NetworkX version: %s" % networkx.__version__)
        logging.info("Python Image Library version: %s" % Image.VERSION)

        self.setupUi(self)
        self._mdiArea.hide()
        self.setWindowTitle("BioPARKIN v%s" % BioParkinController.__version__)

        # restore previous settings
        settings = QSettings()
        try:
            self.recentFiles = settings.value("RecentFiles", [])

            # handles the case if only one file is in the "list" in Linux (it's retrieved as unicode string in this case)
            if type(self.recentFiles) is str or type(self.recentFiles) is unicode:
                self.recentFiles = [self.recentFiles]

            logging.info("Recently opened files: %s" % self.recentFiles)
        except:
            logging.warning("Can't access list of recently opened files. Resetting the list.")
            self.recentFiles = []

        self.updateFileMenu()
        self.aboutDialog = None

        geometry = settings.value("Geometry")
        if geometry:
            self.restoreGeometry(geometry)

        state = settings.value("MainWindow/State")
        if state:
            self.restoreState(state)

        self.ModelControllers = {}
        #        self.SubWindowToModelControllers = {}
        #        self.NetworkWindowCount = 0
        #        self.ActiveNetworkWindow = None
        self.ActiveModelController = None
        #        self.networkSubWindows = {}

        self.integrator = None
        self.odeViewer = None

        self.ModelView = ModelView(self.masterDetailSplitter, self)
        self.ModelTreeView = SBMLEntityWidget(self.masterDetailSplitter)
        self.EntityTableView = EntityTableView(self.masterDetailSplitter)

        self.mainWindowViews = [self.ModelTreeView, self.EntityTableView]  # used to iterate over Views

        # set up Data Service and Data Viewer
        datahandling.parkinController = self
        self.dataService = DataService()

        # debugging#############
        BASE_PATH = reduce(
            lambda l, r: l + os.path.sep + r, os.path.dirname(os.path.realpath(__file__)).split(os.path.sep)[:-1]
        )

        # add ../../templates (relative to the file (!) and not to the CWD)
        dataPath = os.path.join(BASE_PATH, "data")
        #######################

        self.SimulationWorkbenchController = SimulationWorkbenchController(parent=None, parkinController=self)
        self.mainTabWidget.addTab(self.SimulationWorkbenchController, "Workbench")

        # hook up status bar with progress service (that threads can connect to)
        self.statusBarService = StatusBarService(
            self.statusBar()
        )  # first time, service is instantiated => give statusBar reference!
        self.progressBarService = ProgressBarService(self, self.statusBarService)

        self.statusBarLoggingHandler.setStatusBar(self.statusBarService)

        self.warningsService = WarningService.getInstance()
        self.warningsDialog = WarningsDialog(self, self.actionShow_Warnings, self.warningsService)

        # register signals
        self.activeModelChanged.connect(self.on_activeModelChanged)
        self.modelClosed.connect(self.on_modelClosed)
        self.menuFile.aboutToShow.connect(self.updateFileMenu)

        # for debugging
        self.dummyThread = None

        try:  # try to set correct taskbar icon in Windows 7
            myappid = "ZIB.BioPARKIN"  # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        except:
            pass
Beispiel #20
0
class DataBrowser(QWidget, Ui_DataBrowser):
    """
    @since: 2011-08-24
    """
    __author__ = "Moritz Wade"
    __contact__ = "*****@*****.**"
    __copyright__ = "Zuse Institute Berlin 2011"


    def __init__(self, parent, id, dataSet):
        super(DataBrowser, self).__init__(parent)
        self.setupUi(self)

        self._simWorkbench = None
        self.dataService = None

        self.id = id
        self.data = dataSet

        self.optionsService = OptionsService()

        # create the custom selectable table header
        self.selectableHeader = SelectableTableHeader(Qt.Horizontal, self.tableView)
        self.selectableHeader.setNonSelectableIndexes([0])
        self.selectableHeader.sectionSelectionChanged.connect(self.on_columnSelectionChanged)

        self.tableView.setHorizontalHeader(self.selectableHeader)

        # create the data model
        self.dataModel = DataBrowserModel(self, self.id, self.data)
        self.tableView.setModel(self.dataModel)

        self._setUpSelectionCheckBox()
        self._updateInfoPane()

        if not self.optionsService.getDebug():
            self.groupBoxPerturbation.setVisible(False)


    def getId(self):
        return self.id

    def setSimulationWorkbench(self, simWorkbench):
        self._simWorkbench = simWorkbench

    def getSelectionCheckBox(self):
        return self._selectionCheckBox

    def isSelected(self):
        checkState = self._selectionCheckBox.checkState()
        return True if checkState == Qt.Checked else False


    def _setUpSelectionCheckBox(self):
        self._selectionCheckBox = QCheckBox()
        self._selectionCheckBox.setChecked(True)
        infoText = "Select or deselect this data (e.g. to be included in plots and computations)."
        self._selectionCheckBox.setStatusTip(infoText)
        self._selectionCheckBox.setToolTip(infoText)

        self._selectionCheckBox.stateChanged.connect(self._selectionChanged)

    def _updateInfoPane(self):
        """
        Updates the info pane with basic info about the loaded data
        and the data file (if any).
        """
        self.lineEditInfoSpecies.setText(str(self.data.getNumOfRealData()))
        self.lineEditInfoDataType.setText(self.data.type)

        #        self.lineEditInfoFormat.setText(self.data.format)

        filepath = self.data.filename
        if filepath and os.path.exists(filepath):
            self.lineEditInfoPath.setText(filepath)

            filesize = os.path.getsize(filepath)
            filesize = filesize / 1024 # displaying kB
            self.lineEditInfoFilesize.setText("%s kB" % filesize)

            timeLastModifiedEpoch = os.path.getmtime(filepath)
            timeLastModified = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(timeLastModifiedEpoch))
            self.lineEditInfoLastModified.setText(str(timeLastModified))
        else:
            noFileText = "No File"
            self.lineEditInfoPath.setText(noFileText)
            self.lineEditInfoFilesize.setText(noFileText)
            self.lineEditInfoLastModified.setText(noFileText)


    def remove(self):
        """
        Cleans up stuff then destroys self.

        It's not sure whether this is really needed
        but it might serve to close some memory holes
        (e.g. dangling references somewhere).
        """
        del self.dataModel
        del self

    @Slot()
    def on_actionPlot_triggered(self):
        dataDict = {self.data.getId(): self.data}
        self._simWorkbench.plotExpData(dataDict)

    @Slot()
    def on_buttonPerturb_clicked(self):
        """
        Perturbs the data by the % given
        in self.spinBoxPerturb.
        """
        percentage = self.spinBoxPerturb.value()
        factor = percentage / 100.0

        for entity, entityData in self.data.getData().items():
            if not entityData.isSelected():
                continue
            id = entity.getId() if type(entity) == EntityData else str(entity)
            logging.debug("Perturbing data of EntityData: %s" % id)
            for i in xrange(len(entityData.datapoints)):
                value = entityData.datapoints[i]
                if not value:   # for None values
                    continue
                fraction = value * factor   # fraction of value that will be added or substracted
                #newValue = value + random.uniform(-1 * fraction, fraction)
                newValue = value + random.uniform(-1, 1) * fraction
                #                    newValue = value - fraction if random.random() < 0.5 else value + fraction
                entityData.setDatapoint(i, newValue)

    @Slot("")
    def on_buttonSaveAs_clicked(self):
        logging.debug("Saving data. Displaying file chooser...")
        file_choices = "Tab-Delimited Text File *.txt (*.txt)"

        path = unicode(QFileDialog.getSaveFileName(self, 'Save file', '', file_choices)[0])

        if not path.endswith(".txt"):
            path += ".txt"

        if path:
            if not self.dataService:
                self.dataService = DataService()

            id = self.data.getId()
            self.dataService.save_data_as_csv(id, path)
            logging.info("Saved data to %s" % path)


    @Slot()
    def on_buttonTimeshift_clicked(self):
        """
        Timeshift data within this DataBrowser (i.e. DataSet).
        Not only shift the global timepoints but also the timepoint lists
        within the individiual EntityData objects.
        """
        try:
            shiftValue = float(self.lineEditTimeshift.text())
            self.dataModel.doTimeshift(shiftValue)
        except Exception, e:
            logging.error("DataBrowser.on_buttonTimeshift_clicked(): Error while timeshifting the data: %s" % e)
Beispiel #21
0
    def __init__(self, args, parent=None):
        """
        This initialization does a lot of stuff. :)

        * State variables are set up
        * Views are created and tied to UI parts (e.g. Docks)
        * Logging is set up
        * Services (StatusBar, Data, ...) are started
        * Necessary slots are connected

        """
        super(BioParkinController, self).__init__(parent)

        #locale.setlocale(locale.LC_ALL, 'de_DE')
        #        locale.setlocale(locale.LC_ALL, 'deu_deu')

        self.startTime = time.localtime()


        # set file logger
        self.rotatingFileHandler = logging.handlers.RotatingFileHandler(_LOG_FILENAME,
                                                       maxBytes=1000000,
                                                       backupCount=5)
        self.rotatingFileHandler.setFormatter(logging.Formatter("%(asctime)s | %(levelname)s | %(message)s"))
        self.logger = logging.getLogger() #gets root logger
        self.logger.addHandler(self.rotatingFileHandler)

        # Status bar logger
        self.statusBarLoggingHandler = StatusBarLoggingHandler()
        self.statusBarLoggingHandler.setLevel(logging.INFO) # only log on info level
        self.logger.addHandler(self.statusBarLoggingHandler)


        # set GUI logger
        #        self.loggingView = QtLoggingView(self)
        #        loggingHandler = QtLoggingHandler(self.loggingView)
        #        loggingHandler.setLevel(logging.INFO)
        #        self.logger.addHandler(loggingHandler)

        # filling log dock area (was set up in QtDesigner)
        #        self._logDockWidget.setWidget(self.loggingView)
        #        self._logDockWidget.hide()


        # parse command line arguments
        parser = OptionParser()
        parser.add_option("-d", "--debug",
                  action="store_true", dest=OPTION_DEBUG, default=False,
                  help="Include debugging information in console and file log")
        self.options, args = parser.parse_args()

        self.optionsService = OptionsService()
        self.optionsService.setDebug(self.options.debug)

        # set logging options
        if self.options.debug:
            self.logger.setLevel(logging.DEBUG)
            self.rotatingFileHandler.setLevel(logging.DEBUG)
            logging.info("Debug logging active.")
        else:
            self.logger.setLevel(logging.INFO)
            self.rotatingFileHandler.setLevel(logging.INFO)
            logging.info("Debug logging not active.")

        logging.debug("Starting BioPARKIN... %s" % self.startTime)

        ##### LOGGING #####
        logging.info("BioPARKIN started (version %s)" % BioParkinController.__version__)
        logging.info("Command line arguments: %s" % args)
        logging.info("Python version: %s" % sys.version)
#        logging.info("SIP version: %s" % sip.SIP_VERSION_STR)
        #logging.info("PyQt version: %s" % PYQT_VERSION_STR)
        logging.info("PySide version: %s" % PySide.__version__)
        logging.info("libSBML version: %s" % LIBSBML_VERSION_STRING)
        logging.info("Matplotlib version: %s" % matplotlib.__version__)
#        logging.info("NetworkX version: %s" % networkx.__version__)
        logging.info("Python Image Library version: %s" % Image.VERSION)






        self.setupUi(self)
        self._mdiArea.hide()
        self.setWindowTitle("BioPARKIN v%s" % BioParkinController.__version__)

        # restore previous settings
        settings = QSettings()
        try:
            self.recentFiles = settings.value("RecentFiles", [])

            # handles the case if only one file is in the "list" in Linux (it's retrieved as unicode string in this case)
            if type(self.recentFiles) is str or type(self.recentFiles) is unicode:
                self.recentFiles = [self.recentFiles]
                
            logging.info("Recently opened files: %s" % self.recentFiles)
        except:
            logging.warning("Can't access list of recently opened files. Resetting the list.")
            self.recentFiles = []

        self.updateFileMenu()
        self.aboutDialog = None

        geometry = settings.value("Geometry")
        if geometry:
            self.restoreGeometry(geometry)

        state = settings.value("MainWindow/State")
        if state:
            self.restoreState(state)


        self.ModelControllers = {}
#        self.SubWindowToModelControllers = {}
#        self.NetworkWindowCount = 0
#        self.ActiveNetworkWindow = None
        self.ActiveModelController = None
#        self.networkSubWindows = {}

        self.integrator = None
        self.odeViewer = None

        self.ModelView = ModelView(self.masterDetailSplitter, self)
        self.ModelTreeView = SBMLEntityWidget(self.masterDetailSplitter)
        self.EntityTableView = EntityTableView(self.masterDetailSplitter)
#        self.masterDetailSplitter.widget(0).destroy()
#        logging.debug("1st Child of Splitter: %s" % self.masterDetailSplitter.widget(0))

        self.mainWindowViews = [self.ModelTreeView, self.EntityTableView]   #used to iterate over Views



        # set up Data Service and Data Viewer
        datahandling.parkinController = self
        self.dataService = DataService()


        # debugging#############
        BASE_PATH = reduce(lambda l, r: l + os.path.sep + r,
                           os.path.dirname(os.path.realpath(__file__)).split(os.path.sep)[:-1])
        #BASE_PATH = os.path.dirname(os.path.realpath(__file__))

        # add ../../templates (relative to the file (!) and not to the CWD)
        dataPath = os.path.join(BASE_PATH, "data")
        #######################

        self.SimulationWorkbenchController = SimulationWorkbenchController(parent=None, parkinController=self)
        self.mainTabWidget.addTab(self.SimulationWorkbenchController, "Workbench")




        # hook up status bar with progress service (that threads can connect to)
        self.statusBarService = StatusBarService(self.statusBar()) # first time, service is instantiated => give statusBar reference!
#        self.statusBarService.setStatusBar(self.statusBar())
        self.progressBarService = ProgressBarService(self, self.statusBarService)

        self.statusBarLoggingHandler.setStatusBar(self.statusBarService)

        self.warningsService = WarningService.getInstance()
        self.warningsDialog = WarningsDialog(self, self.actionShow_Warnings, self.warningsService)


        # register signals

#        self.connect(self._mdiArea, SIGNAL("subWindowActivated(QMdiSubWindow*)"), self.on_networkwindow_raised)
        self.activeModelChanged.connect(self.on_activeModelChanged)
#        self.activeModelChanged.connect(self.selectNetworkView) # put into own method -> easier to put in own class later
        self.modelClosed.connect(self.on_modelClosed)
#        self.modelClosed.connect(self.closeNetworkWindow) # put into own method -> easier to put in own class later
        self.menuFile.aboutToShow.connect(self.updateFileMenu)


        # for debugging
        self.dummyThread = None

        try:    # try to set correct taskbar icon in Windows 7
            myappid = 'ZIB.BioPARKIN' # arbitrary string
            ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid)
        except:
            pass
Beispiel #22
0
class DataViewingController(QDialog, Ui_DataViewWidget):
    '''
    A experimentalData view window (implemented as DockWidget, so it 
    can be docked inside the main application potentially)
    to display plots, etc. (Maybe more than just plots in a future release?)
    
    In MVC-naming this is the Controller. The View is in Ui_dataViewWidget.
    
    @param parent: Standard Qt UI parent
    @type parent: QWidget
    
    @since: 2010-03-10
    '''

    __author__ = "Moritz Wade"
    __contact__ = "*****@*****.**"
    __copyright__ = "Zuse Institute Berlin 2010"

    def __init__(self, parent=None):
        '''
        Creates a data model from the data (so that changes in the data
        are reflected in the View).
        
        '''
        super(DataViewingController, self).__init__(parent)
        self.setupUi(self)

        self.dataService = DataService()
        experimentalData = self.dataService.get_experimental_data()
        simulationData = self.dataService.get_simulation_data()

        #data = ordereddict()
        self.data = OrderedDict()
        if simulationData is not None and len(simulationData) > 0:
            self.simulationData = simulationData
            for (sbmlEntity, entityData) in self.simulationData.items():
                #sbmlRef = entityData.sbmlEntity
                dataTuple = (entityData, None)
                self.data[sbmlEntity] = dataTuple
        else:
            self.simulationData = None

        if experimentalData is not None:
            self.experimentalData = experimentalData
            for (sbmlEntity, entityData) in experimentalData.items():
                #sbmlRef = entityData.sbmlEntity
                if sbmlEntity in self.data:
                    dataTuple = self.data[sbmlEntity]
                    dataTuple = (dataTuple[0], entityData)
                    self.data[sbmlEntity] = dataTuple
                else:
                    dataTuple = (entityData, None)
                    self.data[sbmlEntity] = dataTuple
        else:
            self.experimentalData = None

        if self.experimentalData or self.simulationData:
            self.dataModel = SourcesTableModel(
                combinedData=self.data
                #experimentalData = self.experimentalData,
                #simulationData = self.simulationData
            )
            self.connect(self.dataModel,
                         SIGNAL("dataChanged(QModelIndex, QModelIndex)"),
                         self.update_plots)

        #self.data = []  # create single list with all data entities
#        for item in self.experimentalData:
#            self.data.append(item)
#        for item in self.simulationData:
#            if item in self.data:
#                continue
#            self.data.append(item)

        self.populate_sources_table()

        #        self.plotWindows = {}
        #        self.flatListOfPlotWidgets = []
        self.existingPlotWindows = {}
        self.update_plots()  # testing
        #QTimer.singleShot(0, self.update_plots)

    def populate_sources_table(self):
        '''
        Sets the "sources" data model to the source table view.
        '''
        if self.dataModel is None:
            logging.error(
                "There is no model to populate with experimental Data.")
            return

        table = self.tableSources
        table.setModel(self.dataModel)

    def update_plots(self):
        '''
        Create all the plots based on the selection in the list widget 
        self.tableSources
        
        This is rather complicated and should be refactored + broken
        down.
        '''

        # gather information about what to show
        windowTitlesToShow = {}
        #for (dataID, dataItem) in self.experimentalData.items():
        for (entity, dataTuple) in self.data.items():
            dataID = entity.id
            if self.dataModel.does_show_experimental_data_of(
                    dataID) and self.dataModel.does_show_simulation_data_of(
                        dataID):
                windowTitle = "Experimental and simulation values of %s" % dataID
            elif self.dataModel.does_show_experimental_data_of(dataID):
                windowTitle = "Experimental values of %s" % dataID
            elif self.dataModel.does_show_simulation_data_of(dataID):
                windowTitle = "Simulation values of %s" % dataID
            else:
                windowTitle = None

            if windowTitle is not None:
                windowTitlesToShow[windowTitle] = (entity, dataTuple)

        # close previous windows that show information we don't want now
        for existingWindowTitle in self.existingPlotWindows.keys():
            if not windowTitlesToShow.has_key(existingWindowTitle):
                self.existingPlotWindows.pop(existingWindowTitle).close()

        # create missing windows
        #for (dataID, dataItem) in self.experimentalData.items():
        for (windowTitle, (entity, dataTuple)) in windowTitlesToShow.items():

            dataID = entity.id

            if self.existingPlotWindows.has_key(
                    windowTitle
            ):  # dont' create windows that are already there
                continue

            labelExperimental = "Experimental values of %s" % dataID
            labelSimulation = "Simulation values of %s" % dataID

            subWindow = QMdiSubWindow(parent=self.plotWindowsArea)
            subWindow.setAttribute(Qt.WA_DeleteOnClose)
            subWindow.setOption(QMdiSubWindow.RubberBandResize, True)
            self.existingPlotWindows[windowTitle] = subWindow

            #            if self.dataModel.does_show_experimental_data_of(dataID):
            #                if self.simulationData.has_key(dataID):
            #                    experimentalData = {dataID:dataItem}
            #                else:
            #                    experimentalData = None
            #            else:
            #                experimentalData = None
            #
            #            if self.dataModel.does_show_simulation_data_of(dataID):
            #                if self.simulationData.has_key(dataID):
            #                    simulationData = {dataID + "_sim" : self.simulationData[dataID]}
            #                else:
            #                    simulationData = None
            #            else:
            #                simulationData = None

            if self.dataModel.does_show_experimental_data_of(dataID):
                experimentalData = dataTuple[1]
            else:
                experimentalData = None

            if self.dataModel.does_show_simulation_data_of(dataID):
                simulationData = dataTuple[0]
            else:
                simulationData = None

            plotWidget = PlotWidget(
                parent=subWindow,
                experimentalData=experimentalData,
                simulationData=simulationData,
                labelExperimental=labelExperimental,
                labelSimulation=labelSimulation,
                showLegend=self.checkBoxShowLegend.isChecked(),
                logYAxis=self.checkBoxLogYAxis.isChecked())

            subWindow.setWindowTitle(windowTitle)
            subWindow.setWidget(plotWidget)
            subWindow.show()  # important!

    @Slot("bool")
    def on_checkBoxPlotGroupsAsTabs_toggled(self, isChecked):
        '''
        This is a slot for toggling a tab UI for the plots,
        '''
        logging.info("Plot Groups are shown as Tabs: %s" % isChecked)
        if isChecked:
            self.plotGroupsArea.setViewMode(QMdiArea.TabbedView)
        else:
            self.plotGroupsArea.setViewMode(QMdiArea.SubWindowView)

    @Slot("QTableWidgetItem")
    def on_tableSources_itemChanged(self, item):
        '''
        This is a slot. Whenever some item changes in the list view 
        (e.g. some data gets checked/unchecked), the plots are updated.
        '''
        self.update_plots()

    @Slot("")
    def on_pushButtonReplot_clicked(self):
        '''
        This is a slot. It causes the plots to be replotted.
        '''
        for existingWindowTitle in self.existingPlotWindows.keys():
            self.existingPlotWindows.pop(existingWindowTitle).close()
        self.update_plots()