Ejemplo n.º 1
0
class FlowTaskPane(TaskPane):
    """
    The center pane for the UI; contains the matplotlib canvas for plotting
    data views.
    """
    
    id = 'edu.mit.synbio.cytoflow.flow_task_pane'
    name = 'Cytometry Data Viewer'
    
    layout = Instance(QtGui.QVBoxLayout)                    # @UndefinedVariable
    canvas = Instance(FigureCanvasQTAggLocal)
    waiting_image = ImageResource('gear')
        
    def create(self, parent):
        if self.canvas is not None:
            return
        
        # create a layout for the tab widget and the main view
        self.layout = layout = QtGui.QVBoxLayout()          # @UndefinedVariable
        self.control = QtGui.QWidget()                      # @UndefinedVariable
        self.control.setLayout(layout)
        
        tabs_ui = self.model.edit_traits(view = 'plot_view',
                                         kind = 'subpanel',
                                         parent = parent)
        self.layout.addWidget(tabs_ui.control) 
        
        # add the main plot
        self.canvas = FigureCanvasQTAggLocal(Figure(), 
                                             self.model.child_matplotlib_conn, 
                                             self.waiting_image.create_image(size = (1000, 1000)))
        self.canvas.setSizePolicy(QtGui.QSizePolicy.Expanding,  # @UndefinedVariable
                                  QtGui.QSizePolicy.Expanding)  # @UndefinedVariable
        
        layout.addWidget(self.canvas)
                  
    def export(self, filename, **kwargs):      
        self.canvas.print_figure(filename, bbox_inches = 'tight', **kwargs)
Ejemplo n.º 2
0
    def image_resource(self, image_name):
        """ Returns the ImageResource object for the specified **image_name**.
        """
        # Get the name of the image file:
        volume_name, file_name = split_image_name(image_name)

        if self.is_zip_file:
            # See if we already have the image file cached in the file system:
            cache_file = self._check_cache(file_name)
            if cache_file is None:
                # If not cached, then create a zip file reference:
                ref = ZipFileReference(
                    resource_factory=resource_manager.resource_factory,
                    zip_file=self.zip_file,
                    path=self.path,
                    volume_name=self.name,
                    file_name=file_name,
                )
            else:
                # Otherwise, create a cache file reference:
                ref = ImageReference(
                    resource_manager.resource_factory, filename=cache_file
                )
        else:
            # Otherwise, create a normal file reference:
            ref = ImageReference(
                resource_manager.resource_factory,
                filename=join(self.path, file_name),
            )

        # Create the ImageResource object using the reference (note that the
        # ImageResource class will not allow us to specify the reference in the
        # constructor):
        resource = ImageResource(file_name)
        resource._ref = ref

        # Return the ImageResource:
        return resource
Ejemplo n.º 3
0
class EEGSensorApp(t.HasTraits):

    sensor = t.Instance(EEGSensor)
    filters = t.List(t.Instance(TimeDomainFilter))

    sensor_operation_controller = t.Instance(SensorOperationController)

    def _sensor_operation_controller_default(self):
        return SensorOperationController(model=self.sensor)

    sensor_timeseries_controller = t.Instance(SensorTimeseriesController)

    def _sensor_timeseries_controller_default(self):
        return SensorTimeseriesController(model=self.sensor,
                                          filters=self.filters)

    sensor_fft_controller = t.Instance(SensorFFTController)

    def _sensor_fft_controller_default(self):
        return SensorFFTController(model=self.sensor)

    traits_view = QtView(
        HGroup(
            VGroup(Item('sensor_timeseries_controller', style='custom'),
                   show_border=True,
                   show_labels=False),
            VGroup(Item('sensor_fft_controller', style='custom'),
                   Item('sensor_operation_controller', style='custom'),
                   show_border=True,
                   show_labels=False),
        ),
        title="EEG Sensor Console",
        icon=ImageResource('application'),
        # style_sheet_path='dark_style_sheet.qss',
        style_sheet=qdarkstyle.load_stylesheet(pyside=True),
        resizable=True,
        handler=AppHandler(),
    )
Ejemplo n.º 4
0
class SecondTask(ExampleTask):
    """ A simple task for opening a blank editor.
    """

    # Task interface -------------------------------------------------------

    id = "example.second_task"
    name = "Second Multi-Tab Editor"

    menu_bar = SMenuBar(
        SMenu(
            TaskAction(name="New", method="new", accelerator="Ctrl+N"),
            id="File",
            name="&File",
        ),
        SMenu(DockPaneToggleGroup(),
              TaskToggleGroup(),
              id="View",
              name="&View"),
    )

    tool_bars = [
        SToolBar(
            TaskAction(
                method="new",
                tooltip="New file",
                image=ImageResource("document_new"),
            ),
            image_size=(32, 32),
        )
    ]

    # ------------------------------------------------------------------------
    # 'Task' interface.
    # ------------------------------------------------------------------------

    def _default_layout_default(self):
        return TaskLayout(bottom=PaneItem("steps.example_pane"))
Ejemplo n.º 5
0
class LorenzApplication(WorkbenchApplication):
    """ The Lorenz example application. """

    #### 'IApplication' interface #############################################

    # The application's globally unique Id.
    id = 'acme.lorenz'

    #### 'WorkbenchApplication' interface #####################################

    # Branding information.
    #
    # The icon used on window title bars etc.
    icon = ImageResource('lorenz.ico')

    # The name of the application (also used on window title bars etc).
    name = 'Lorenz'

    ###########################################################################
    # 'WorkbenchApplication' interface.
    ###########################################################################

    def _about_dialog_default(self):
        """ Trait initializer. """

        about_dialog = AboutDialog(parent=self.workbench.active_window.control,
                                   image=ImageResource('about'))

        return about_dialog

    def _splash_screen_default(self):
        """ Trait initializer. """

        splash_screen = SplashScreen(image=ImageResource('splash'),
                                     show_log_messages=True,
                                     log_level=DEBUG)

        return splash_screen
Ejemplo n.º 6
0
    def create_contents(self, parent):
        """ 
        Create and return the toolkit-specific contents of the dock pane.
        """

        self.toolbar = ToolBarManager(orientation='vertical',
                                      show_tool_names=False,
                                      image_size=(32, 32))

        self._default_action = TaskAction(
            name="Setup View",
            on_perform=lambda: self.task.set_current_view("default"),
            image=ImageResource('setup'),
            style='toggle',
            visible=False)
        self._actions["default"] = self._default_action
        self.toolbar.append(self._default_action)

        for plugin in self.plugins:
            task_action = TaskAction(name=plugin.short_name,
                                     on_perform=lambda id=plugin.view_id: self.
                                     task.set_current_view(id),
                                     image=plugin.get_icon(),
                                     style='toggle')
            self._actions[plugin.view_id] = task_action
            self.toolbar.append(task_action)

        window = QtGui.QMainWindow()
        window.addToolBar(QtCore.Qt.RightToolBarArea,
                          self.toolbar.create_tool_bar(window))

        self.ui = self.edit_traits(kind='subpanel', parent=window)
        window.setCentralWidget(self.ui.control)

        window.setParent(parent)
        parent.setWidget(window)

        return window
Ejemplo n.º 7
0
    def on_about(self):
        versions = self._get_package_versions()
        text = ["<b>Cytoflow {0}</b>".format(versions['cytoflow']), "<p>"]

        ver_text = [
            "{0} {1}".format(key, value) for key, value in versions.items()
        ]

        text.extend(ver_text)

        text.extend([
            "Icons from the <a href=http://tango.freedesktop.org>Tango Desktop Project</a>",
            "<a href=https://thenounproject.com/search/?q=setup&i=14287>Settings icon</a> by Paulo Sa Ferreira from <a href=https://thenounproject.com>The Noun Project</a>",
            "<a href=http://www.freepik.com/free-photos-vectors/background>App icon from Starline - Freepik.com</a>",
            "Cuvette image from Wikimedia Commons user <a href=http://commons.wikimedia.org/wiki/File:Hellma_Large_cone_cytometry_cell.JPG>HellmaUSA</a>"
        ])

        dialog = AboutDialog(text=text,
                             parent=self.window.control,
                             title="About",
                             image=ImageResource('cuvette'),
                             additions=text)
        dialog.open()
class CorrectedDatasetsNode(TreeNode):

    # List of object classes the node applies to
    node_for = [CorrectedDatasets]

    # Automatically open the children underneath the node
    auto_open = False

    # Specify children of node (this is an attribute of the class in
    # 'node_for')
    children = 'datasets'

    # Label of the node (this is an attribute of the class in 'node_for')
    label = 'title'

    # View for the node
    view = View(Group('title', orientation='vertical', show_left=False))

    # Class of node to add
    add = [Dataset]

    icon_group = ImageResource('../images/sample_and_container.png')
    icon_open = icon_group
Ejemplo n.º 9
0
class SceneAdderNode(AdderNode):
    """ Subclass for adding Scene nodes to a Mayavi Engine node.
    """

    # String to be shown in the TreeEditor.
    label = Str('Add a new scene')

    # The name of the icon
    icon_name = Str('add_scene.png')

    # Button for the View.
    add_scene = Button('Add a new scene',
                      image=ImageResource('add_scene.png'))

    # Trait view to show in the Mayavi current object panel.
    view = View(Group(Item('add_scene', show_label=False, style='custom'),
                      label='Add a scene'))


    def _add_scene_fired(self):
        """ Trait handler for when the add_scene button is clicked.
        """
        self.object.new_scene()
Ejemplo n.º 10
0
    def init ( self, parent ):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        self._uis = []

        # Create a tab widget to hold each separate object's view:
        self.control = QtGui.QTabWidget()
        signal = QtCore.SIGNAL( 'currentChanged(int)' )
        QtCore.QObject.connect( self.control, signal, self._tab_activated )

        # Create the button to close tabs, if necessary:
        if self.factory.deletable:
            button = QtGui.QToolButton()
            button.setAutoRaise( True )
            button.setToolTip( 'Remove current tab ')
            button.setIcon ( ImageResource( 'closetab' ).create_icon() )

            self.control.setCornerWidget( button, QtCore.Qt.TopRightCorner )
            signal = QtCore.SIGNAL( 'clicked()' )
            QtCore.QObject.connect( button, signal, self.close_current )
            self.close_button = button

        if self.factory.show_notebook_menu:
            # Create the necessary attributes to manage hiding and revealing of
            # tabs via a context menu
            self._context_menu = QtGui.QMenu()
            self.control.customContextMenuRequested.connect(self._context_menu_requested)
            self.control.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)

        # Set up the additional 'list items changed' event handler needed for
        # a list based trait:
        self.context_object.on_trait_change( self.update_editor_item,
                               self.extended_name + '_items?', dispatch = 'ui' )

        # Set of selection synchronization:
        self.sync_value( self.factory.selected, 'selected' )
Ejemplo n.º 11
0
 def _tool_bars_default(self):
     toolbars = [
         SToolBar(TaskAction(name="Import",
                             method='on_import',
                             image=ImageResource('import')),
                  TaskAction(name="Open",
                             method='on_open',
                             image=ImageResource('survey')),
                  TaskAction(name="Save",
                             method='on_save',
                             enabled_name='dirty',
                             image=ImageResource('save')),
                  id='File',
                  name="File",
                  show_tool_names=False,
                  image_size=(24, 24)),
         SToolBar(TaskCommandAction(name='New Group',
                                    method='on_new_group',
                                    command_stack_name='command_stack',
                                    image=ImageResource('new-group')),
                  TaskCommandAction(name='Delete Group',
                                    method='on_delete_group',
                                    enabled_name='have_current_group',
                                    command_stack_name='command_stack',
                                    image=ImageResource('delete-group')),
                  TaskAction(name='Previous Line',
                             method='on_previous_line',
                             enabled_name='survey.survey_lines',
                             image=ImageResource("arrow-left")),
                  TaskAction(name='Next Line',
                             method='on_next_line',
                             enabled_name='survey.survey_lines',
                             image=ImageResource("arrow-right")),
                  id='Survey',
                  name="Survey",
                  show_tool_names=False,
                  image_size=(24, 24)),
     ]
     return toolbars
Ejemplo n.º 12
0
class SecondTask(ExampleTask):
    """ A simple task for opening a blank editor.
    """

    #### Task interface #######################################################

    id = 'example.second_task'
    name = 'Second Multi-Tab Editor'

    menu_bar = SMenuBar(
        SMenu(TaskAction(name='New', method='new', accelerator='Ctrl+N'),
              id='File',
              name='&File'),
        SMenu(DockPaneToggleGroup(),
              TaskToggleGroup(),
              id='View',
              name='&View'))

    tool_bars = [
        SToolBar(TaskAction(method='new',
                            tooltip='New file',
                            image=ImageResource('document_new')),
                 image_size=(32, 32)),
    ]

    ###########################################################################
    # 'Task' interface.
    ###########################################################################

    def _default_layout_default(self):
        return TaskLayout(left=VSplitter(
            HSplitter(PaneItem('steps.pane1'), PaneItem('steps.pane2'),
                      PaneItem('steps.pane3')),
            HSplitter(PaneItem('steps.pane4'), PaneItem('steps.pane5'),
                      PaneItem('steps.pane6')),
        ))
class EditPreferencesAction(Action):
    """ An action that displays the preferences dialog. """

    #### 'Action' interface ###################################################

    # A longer description of the action.
    description = 'Manage Preferences'

    # The action's image (displayed on tool bar tools etc).
    image = ImageResource('preferences')

    # The action's name (displayed on menus/tool bar tools etc).
    name = 'Preferences'

    # A short description of the action used for tooltip text etc.
    tooltip = 'Manage Preferences'

    ###########################################################################
    # 'Action' interface.
    ###########################################################################

    def perform(self, event):
        """ Performs the action. """

        from apptools.preferences.ui.api import PreferencesManager

        # Lookup the preferences manager service.
        manager = event.window.application.get_service(PreferencesManager)
        ui = manager.edit_traits(parent=event.window.control, kind='modal')

        # If the user hit the "Ok" button, then save the preferences in case
        # application crashes before it exits!
        if ui.result:
            self.window.application.preferences.save()

        return
Ejemplo n.º 14
0
 def get_icon(self):
     return ImageResource('kmeans')
Ejemplo n.º 15
0
class FlowTask(Task):
    """
    classdocs
    """

    id = "edu.mit.synbio.cytoflow.flow_task"
    name = "Cytometry analysis"

    # the main workflow instance.
    # THIS IS WHERE IT'S INITIALLY INSTANTIATED (note the args=())
    model = Instance(Workflow, args=())

    # the center pane
    view = Instance(FlowTaskPane)

    # plugin lists, to setup the interface
    op_plugins = List(IOperationPlugin)
    view_plugins = List(IViewPlugin)

    menu_bar = SMenuBar(
        SMenu(
            TaskAction(name='Open...', method='on_open', accelerator='Ctrl+O'),
            TaskAction(
                name='Save',
                #image='save',
                method='on_save',
                accelerator='Ctrl+S'),
            TaskAction(name='Save As...',
                       method='on_save_as',
                       accelerator='Ctrl+e'),
            TaskAction(name='Export image...',
                       method='on_export',
                       accelerator='Ctrl+x'),
            TaskAction(name='Export IPython notebook...',
                       method='on_ipython',
                       accelerator='Ctrl+I'),
            TaskAction(name='Preferences...',
                       method='on_prefs',
                       accelerator='Ctrl+P'),
            id='File',
            name='&File'),
        SMenu(TaskAction(name='About...',
                         method='on_about',
                         accelerator="Ctrl+A"),
              id="Help",
              name="&Help"))

    tool_bars = [
        SToolBar(TaskAction(method='on_new',
                            name="New",
                            tooltip='New workflow',
                            image=ImageResource('new')),
                 TaskAction(method='on_open',
                            name="Open",
                            tooltip='Open a file',
                            image=ImageResource('open')),
                 TaskAction(method='on_save',
                            name="Save",
                            tooltip='Save the current file',
                            image=ImageResource('save')),
                 TaskAction(method='on_export',
                            name="Export",
                            tooltip='Export the current plot',
                            image=ImageResource('export')),
                 TaskAction(method='on_ipython',
                            name='IPython',
                            tooltip="Export to an IPython notebook...",
                            image=ImageResource('ipython')),
                 TaskAction(method='on_prefs',
                            name="Prefs",
                            tooltip='Preferences',
                            image=ImageResource('prefs')),
                 image_size=(32, 32))
    ]

    # are we debugging?  ie, do we need a default setup?
    debug = Bool

    worker = Instance(threading.Thread)
    to_update = Instance(UniquePriorityQueue, ())
    worker_flag = Instance(threading.Event, args=())
    worker_lock = Instance(threading.Lock, args=())

    def initialized(self):

        # make sure that when the result changes we get notified
        # can't use a static notifier because selected.result gets updated
        # on the worker thread, but we need to dispatch on the UI thread
        self.model.on_trait_change(self._result_updated,
                                   "selected:result",
                                   dispatch='ui')

    def activated(self):
        # add an import plugin
        plugin = ImportPlugin()
        wi = WorkflowItem(task=self)
        wi.operation = plugin.get_operation()

        self.model.workflow.append(wi)
        self.model.selected = wi

        # if we're debugging, add a few data bits
        if self.debug:
            from cytoflow import Tube

            wi.operation.conditions["Dox"] = "log"

            tube1 = Tube(file="../cytoflow/tests/data/Plate01/CFP_Well_A4.fcs",
                         conditions={"Dox": 0.1})

            tube2 = Tube(file="../cytoflow/tests/data/Plate01/RFP_Well_A3.fcs",
                         conditions={"Dox": 1.0})

            wi.operation.tubes.append(tube1)
            wi.operation.tubes.append(tube2)

            self.add_operation(
                'edu.mit.synbio.cytoflowgui.op_plugins.threshold')
            self.model.selected.operation.channel = "Y2-A"
            self.model.selected.operation.threshold = 2000
            self.model.selected.operation.name = "T"

    def prepare_destroy(self):
        self.model = None

    def _default_layout_default(self):
        return TaskLayout(left=PaneItem("edu.mit.synbio.workflow_pane"),
                          right=PaneItem("edu.mit.synbio.view_traits_pane"))

    def create_central_pane(self):
        self.view = FlowTaskPane(model=self.model)
        return self.view

    def create_dock_panes(self):
        return [
            WorkflowDockPane(model=self.model,
                             plugins=self.op_plugins,
                             task=self),
            ViewDockPane(model=self.model,
                         plugins=self.view_plugins,
                         task=self)
        ]

    def on_new(self):
        self.model.workflow = []

        # add an import plugin
        plugin = ImportPlugin()
        wi = WorkflowItem(task=self)
        wi.operation = plugin.get_operation()

        self.model.workflow.append(wi)
        self.model.selected = wi

    def on_open(self):
        """ Shows a dialog to open a file.
        """
        dialog = FileDialog(parent=self.window.control,
                            action='open',
                            wildcard='*.flow')
        if dialog.open() == OK:
            self.open_file(dialog.path)

    def open_file(self, path):
        f = open(path, 'r')
        unpickler = pickle.Unpickler(f)
        new_model = unpickler.load()

        # update the link back to the controller (ie, self)
        for wi in new_model.workflow:
            wi.task = self

            # and set up the view handlers
            for view in wi.views:
                view.handler = view.handler_factory(model=view, wi=wi)

        # replace the current workflow with the one we just loaded

        if False:
            from event_tracer import record_events

            with record_events() as container:
                self.model.workflow[:] = new_model.workflow
                self.model.selected = new_model.selected

            container.save_to_directory(os.getcwd())
        else:
            self.model.workflow[:] = new_model.workflow
            self.model.selected = new_model.selected

        wi = self.model.workflow[0]
        while True:
            wi.status = "invalid"
            with self.worker_lock:
                self.to_update.put_nowait((self.model.workflow.index(wi), wi))
            if wi.next:
                wi = wi.next
            else:
                break

        # check to see if we have a worker thread around
        if not self.worker or not self.worker.is_alive():
            self.worker = threading.Thread(target=update_model,
                                           args=(self.worker_flag,
                                                 self.worker_lock,
                                                 self.to_update))
            self.worker.daemon = True
            self.worker.start()

        # start the worker thread processing
        with self.worker_lock:
            if not self.to_update.empty():
                self.worker_flag.set()

    def on_save(self):
        """ Shows a dialog to open a file.
        """
        dialog = FileDialog(parent=self.window.control,
                            action='save as',
                            wildcard='*.flow')
        if dialog.open() == OK:
            self.save_file(dialog.path)

    def on_save_as(self):
        pass

    def save_file(self, path):
        # TODO - error handling
        f = open(path, 'w')
        pickler = pickle.Pickler(f, 0)  # text protocol for now
        pickler.dump(self.model)

    def on_export(self):
        """
        Shows a dialog to export a file
        """
        dialog = FileDialog(parent=self.window.control, action='save as')
        if dialog.open() == OK:
            self.view.export(dialog.path)

    def on_ipython(self):
        """
        Shows a dialog to export the workflow to an IPython notebook
        """

        dialog = FileDialog(parent=self.window.control,
                            action='save as',
                            wildcard='*.ipynb')
        if dialog.open() == OK:
            writer = IPythonNotebookWriter(file=dialog.path)
            writer.export(self.workflow)

    def on_prefs(self):
        pass

    def on_about(self):
        from cytoflow import __version__ as cf_version
        from fcsparser import __version__ as fcs_version
        from pandas.version import __version__ as pd_version
        from numpy.version import version as np_version
        from numexpr import __version__ as numexp_version
        from seaborn import __version__ as sns_version
        from matplotlib import __version__ as mpl_version
        from pyface import __version__ as py_version
        from envisage import __version__ as env_version
        from traits import __version__ as trt_version
        from traitsui import __version__ as trt_ui_version

        text = [
            "<b>Cytoflow {0}</b>".format(cf_version), "<p>",
            "fcsversion {0}".format(fcs_version),
            "pandas {0}".format(pd_version), "numpy {0}".format(np_version),
            "numexpr {0}".format(numexp_version),
            "seaborn {0}".format(sns_version),
            "matplotlib {0}".format(mpl_version),
            "pyface {0}".format(py_version),
            "envisage {0}".format(env_version),
            "traits {0}".format(trt_version),
            "traitsui {0}".format(trt_ui_version),
            "Icons from the <a href=http://tango.freedesktop.org>Tango Desktop Project</a>",
            "<a href=https://thenounproject.com/search/?q=setup&i=14287>Settings icon</a> by Paulo Sa Ferreira from <a href=https://thenounproject.com>The Noun Project</a>",
            "Cuvette image from Wikimedia Commons user <a href=http://commons.wikimedia.org/wiki/File:Hellma_Large_cone_cytometry_cell.JPG>HellmaUSA</a>"
        ]
        dialog = AboutDialog(parent=self.window.control,
                             title="About",
                             image=ImageResource('cuvette'),
                             additions=text)
        dialog.open()

    def add_operation(self, op_id):
        # first, find the matching plugin
        plugin = next((x for x in self.op_plugins if x.id == op_id))

        # default to inserting at the end of the list if none selected
        after = self.model.selected
        if after is None:
            after = self.model.workflow[-1]

        idx = self.model.workflow.index(after)

        wi = WorkflowItem(task=self)
        wi.operation = plugin.get_operation()

        wi.next = after.next
        after.next = wi
        wi.previous = after
        if wi.next:
            wi.next.previous = wi
        self.model.workflow.insert(idx + 1, wi)

        # set up the default view
        wi.default_view = plugin.get_default_view()
        if wi.default_view is not None:
            wi.default_view.op = wi.operation
            wi.default_view.handler = \
                wi.default_view.handler_factory(model = wi.default_view, wi = wi.previous)
            wi.views.append(wi.default_view)

        # select (open) the new workflow item
        self.model.selected = wi
        if wi.default_view:
            wi.current_view = wi.default_view

        # invalidate everything following
        self.operation_parameters_updated()

    @on_trait_change("model:workflow[]")
    def _on_remove_operation(self, obj, name, old, new):
        if name == "workflow_items" and len(new) == 0 and len(old) > 0:
            assert len(old) == 1
            wi = old[0]

            if self.model.selected == wi:
                self.model.selected = wi.previous

            wi.previous.next = wi.next
            if wi.next:
                wi.next.previous = wi.previous

            del wi.default_view
            del wi.views
            del wi

            self.operation_parameters_updated()

    @on_trait_change("model:selected:operation:+")
    def operation_parameters_updated(self):

        # invalidate this workflow item and all the ones following it
        wi = self.model.selected
        while True:
            wi.status = "invalid"
            with self.worker_lock:
                self.to_update.put_nowait((self.model.workflow.index(wi), wi))
            if wi.next:
                wi = wi.next
            else:
                break

        # check to see if we have a worker thread around
        if not self.worker or not self.worker.is_alive():
            self.worker = threading.Thread(target=update_model,
                                           args=(self.worker_flag,
                                                 self.worker_lock,
                                                 self.to_update))
            self.worker.daemon = True
            self.worker.start()

        # start the worker thread processing
        with self.worker_lock:
            if not self.to_update.empty():
                self.worker_flag.set()

    def set_current_view(self, view_id):
        """
        called by the view pane 
        """
        wi = self.model.selected

        if view_id == "default":
            view_id = self.model.selected.default_view.id

        view = next((x for x in wi.views if x.id == view_id), None)

        if not view:
            plugin = next(
                (x for x in self.view_plugins if x.view_id == view_id))
            view = plugin.get_view()
            view.handler = view.handler_factory(model=view, wi=wi)
            wi.views.append(view)

        wi.current_view = view

    @on_trait_change("model:selected.current_view")
    def _current_view_changed(self, obj, name, old, new):

        # we get notified if *either* the currently selected workflowitem
        # *or* the current view changes.

        if name == 'selected':
            new = new.current_view if new else None
            old = old.current_view if old else None

        # remove the notifications from the old view
        if old:
            old.on_trait_change(self.view_parameters_updated, remove=True)

            # and if the old view was interactive, turn off its interactivity
            # to remove the matplotlib event handlers
            if "interactive" in old.traits():
                old.interactive = False

        # whenever the view parameters change, we need to know so we can
        # update the plot(s)
        if new:
            new.on_trait_change(self.view_parameters_updated)

            if self.model.selected:
                self.view.plot(self.model.selected)
            else:
                self.view.clear_plot()
        else:
            self.view.clear_plot()

    def _result_updated(self, obj, name, old, new):
        print "result updated"
        if self.model.selected:
            self.view.plot(self.model.selected)
        else:
            self.view.clear_plot()

    def view_parameters_updated(self, obj, name, new):

        # i should be able to specify the metadata i want in the listener,
        # but there's an odd interaction (bug) between metadata, dynamic
        # trait listeners and instance traits.  so, check for 'transient'
        # here instead,

        if obj.trait(name).transient:
            return

        print "view parameters updated: {0}".format(name)
        wi = self.model.selected
        if wi is None:
            wi = self.model.workflow[-1]

        self.view.plot(wi)
Ejemplo n.º 16
0
        ObjectTreeNode(node_for=[DemoFile],
                       label="nice_name",
                       view=demo_file_view),
        ObjectTreeNode(node_for=[DemoContentFile],
                       label="nice_name",
                       view=demo_content_view),
        ObjectTreeNode(node_for=[DemoImageFile],
                       label="nice_name",
                       view=demo_content_view),
    ],
    selected='selected_node',
)

next_tool = Action(
    name='Next',
    image=ImageResource("next"),
    tooltip="Go to next file",
    action="do_next",
    enabled_when="_next_node is not None",
)

previous_tool = Action(
    name='Previous',
    image=ImageResource("previous"),
    tooltip="Go to next file",
    action="do_previous",
    enabled_when="_previous_node is not None",
)

parent_tool = Action(
    name='Parent',
Ejemplo n.º 17
0
 def _actions_default(self):
     return [
         Group(
             Action(
                 image=ImageResource(
                     '16x16/x-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the -X axis",
                 on_perform=self.x_minus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/x-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the +X axis",
                 on_perform=self.x_plus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/y-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the -Y axis",
                 on_perform=self.y_minus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/y-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the +Y axis",
                 on_perform=self.y_plus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/z-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the -Z axis",
                 on_perform=self.z_minus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/z-axis',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="View along the +Z axis",
                 on_perform=self.z_plus_view,
             ),
             Action(
                 image=ImageResource(
                     '16x16/isometric',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="Obtain an isometric view",
                 on_perform=self.isometric_view,
             ),
         ),
         Group(
             Action(
                 image=ImageResource(
                     '16x16/parallel',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip='Toggle parallel projection',
                 style="toggle",
                 on_perform=self._toggle_projection,
                 checked=self.parallel_projection,
             ),
             Action(
                 image=ImageResource(
                     '16x16/origin_glyph',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip='Toggle axes indicator',
                 style="toggle",
                 enabled=(self.marker is not None),
                 on_perform=self._toggle_axes,
                 checked=self.show_axes,
             ),
             Action(
                 image=ImageResource(
                     '16x16/fullscreen',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip=
                 'Full Screen (press "q" or "e" or ESC to exit fullscreen)',
                 style="push",
                 on_perform=self._full_screen_fired,
             ),
         ),
         Group(
             Action(
                 image=ImageResource(
                     '16x16/save',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip="Save a snapshot of this scene",
                 on_perform=self._save_snapshot,
             ),
             Action(
                 image=ImageResource(
                     '16x16/configure',
                     search_path=[self._get_image_path()],
                 ),
                 tooltip='Configure the scene',
                 style="push",
                 on_perform=self._configure_scene,
             ),
         ),
     ]
Ejemplo n.º 18
0
        info.object.load()


action_strings = \
    [('Plot', 'replot', 'Replot current diagrams'),
     ('Clear', 'clear', 'Clear current diagrams'),
     ('Save', 'save', 'Save session'),
     ('Load', 'load', 'Load session'),
     ('Animate', 'anim', 'Animate current session'),
     ('Render', 'render', 'Render current session')]

toolbar_actions = [
    Action(name="Run",
           tooltip='Start computation',
           enabled_when='enable_run',
           image=ImageResource('kt-start'),
           action="run_action"),
    Action(name="Pause",
           tooltip='Pause computation',
           enabled_when='enable_pause',
           image=ImageResource('kt-pause'),
           action="pause_action"),
    Action(name="Stop",
           tooltip='Stop computation',
           enabled_when='enable_stop',
           image=ImageResource('kt-stop'),
           action="stop_action"),
]

# toolbar_actions += [Action(name=name,
#                            action=action,
Ejemplo n.º 19
0
 def get_icon(self):
     return ImageResource('polygon')
Ejemplo n.º 20
0
class PythonEditorTask(Task):
    """ A simple task for editing Python code.
    """

    # 'Task' traits -----------------------------------------------------------

    #: The unique id of the task.
    id = 'example.python_editor_task'

    #: The human-readable name of the task.
    name = u"Python Editor"

    #: The currently active editor in the editor area, if any.
    active_editor = Property(Instance(IEditor),
                             depends_on='editor_area.active_editor')

    #: The editor area for this task.
    editor_area = Instance(IEditorAreaPane)

    #: The menu bar for the task.
    menu_bar = SMenuBar(
        SMenu(
            SGroup(
                TaskAction(name='New', method='new', accelerator='Ctrl+N'),
                id='new_group',
            ),
            SGroup(
                TaskAction(name='Open...', method='open',
                           accelerator='Ctrl+O'),
                id='open_group',
            ),
            SGroup(
                TaskAction(name='Save',
                           method='save',
                           accelerator='Ctrl+S',
                           enabled_name='active_editor.dirty'),
                TaskAction(name='Save As...',
                           method='save_as',
                           accelerator='Ctrl+Shift+S'),
                id='save_group',
            ),
            SGroup(
                TaskAction(
                    name='Close Editor',
                    method='close_editor',
                    accelerator='Ctrl+W',
                ),
                id='close_group',
            ),
            id='File',
            name='&File',
        ),
        SMenu(
            SGroup(
                EditorAction(
                    name='Undo',
                    method='undo',
                    enabled_name='can_undo',
                    accelerator='Ctrl+Z',
                ),
                EditorAction(
                    name='Redo',
                    method='redo',
                    enabled_name='can_redo',
                    accelerator='Ctrl+Shift+Z',
                ),
                id='undo_group',
            ),
            SGroup(
                EditorAction(
                    name='Go to Line...',
                    method='go_to_line',
                    accelerator='Ctrl+G',
                ),
                id='search_group',
            ),
            id='Edit',
            name='&Edit',
        ), SMenu(
            DockPaneToggleGroup(),
            id='View',
            name='&View',
        ),
        SMenu(
            SGroup(
                OpenURLAction(
                    name='Python Documentation',
                    id='python_docs',
                    url=PYTHON_DOCS,
                ),
                id="documentation_group",
            ),
            id='Help',
            name='&Help',
        ))

    #: The tool bars for the task.
    tool_bars = [
        SToolBar(TaskAction(
            method='new',
            tooltip='New file',
            image=ImageResource('document_new'),
        ),
                 TaskAction(method='open',
                            tooltip='Open a file',
                            image=ImageResource('document_open')),
                 TaskAction(method='save',
                            tooltip='Save the current file',
                            image=ImageResource('document_save'),
                            enabled_name='active_editor.dirty'),
                 image_size=(16, 16),
                 show_tool_names=False),
    ]

    #: The status bar for the window when this task is active.
    status_bar = Instance(StatusBarManager, ())

    # -------------------------------------------------------------------------
    # 'PythonEditorTask' interface.
    # -------------------------------------------------------------------------

    def create_editor(self, path=''):
        """ Create a new editor in the editor pane.

        Parameters
        ----------
        path : path or ''
            The path to the file to edit, or '' for an empty editor.
        """
        if path:
            path = os.path.abspath(path)
        use_existing = (path != '')
        self.editor_area.edit(
            path,
            factory=PythonEditor,
            use_existing=use_existing,
        )
        if path:
            self.active_editor.load()

    def close_editor(self):
        """ Close the active editor, or if no editors, close the Task window.
        """
        if self.editor_area.active_editor is not None:
            self.editor_area.remove_editor(self.editor_area.active_editor)
        else:
            self.window.close()

    def new(self):
        """ Open a new empty window
        """
        self.create_editor()

    def open(self):
        """ Shows a dialog to open a Python file.
        """
        dialog = FileDialog(parent=self.window.control, wildcard='*.py')
        if dialog.open() == OK:
            self.create_editor(dialog.path)

    def save(self):
        """ Save the current file.
        
        If needed, this code prompts for a path.
        
        Returns
        -------
        saved : bool
            Whether or not the file was saved.
        """
        editor = self.active_editor
        try:
            editor.save()
        except IOError:
            # If you are trying to save to a file that doesn't exist, open up a
            # FileDialog with a 'save as' action.
            dialog = FileDialog(
                parent=self.window.control,
                action='save as',
                wildcard='*.py',
            )
            if dialog.open() == OK:
                editor.save(dialog.path)
            else:
                return False
        return True

    # -------------------------------------------------------------------------
    # 'Task' interface.
    # -------------------------------------------------------------------------

    def _default_layout_default(self):
        """ The default layout with the browser pane on the left.
        """
        return TaskLayout(
            left=PaneItem('example.python_browser_pane', width=200))

    def create_central_pane(self):
        """ Create the central pane: the script editor.
        """
        self.editor_area = EditorAreaPane()
        return self.editor_area

    def create_dock_panes(self):
        """ Create the file browser and connect to its double click event.
        """
        browser = PythonBrowserPane()

        def handler():
            return self.create_editor(browser.selected_file)

        browser.on_trait_change(handler, 'activated')
        return [browser]

    # -------------------------------------------------------------------------
    # Protected interface.
    # -------------------------------------------------------------------------

    def _prompt_for_save(self):
        """ Prompts the user to save if necessary. Returns whether the dialog
            was cancelled.
        """
        dirty_editors = {
            editor.name: editor
            for editor in self.editor_area.editors
            if editor.dirty and (editor.obj or editor.code)
        }
        if not dirty_editors:
            return True

        message = 'You have unsaved files. Would you like to save them?'
        dialog = ConfirmationDialog(parent=self.window.control,
                                    message=message,
                                    cancel=True,
                                    default=CANCEL,
                                    title='Save Changes?')
        result = dialog.open()
        if result == CANCEL:
            return False
        elif result == YES:
            for name, editor in dirty_editors.items():
                editor.save(editor.path)
        return True

    # Trait change handlers --------------------------------------------------

    @on_trait_change('window:closing')
    def _prompt_on_close(self, event):
        """ Prompt the user to save when exiting.
        """
        close = self._prompt_for_save()
        event.veto = not close

    @on_trait_change('active_editor.name')
    def _change_title(self):
        """ Update the window title when the active editor changes.
        """
        if self.window.active_task == self:
            if self.active_editor is not None:
                self.window.title = self.active_editor.name
            else:
                self.window.title = self.name

    @on_trait_change('active_editor.[line,column,selection_length]')
    def _update_status(self):
        if self.active_editor is not None:
            editor = self.active_editor
            if editor.selection_length:
                self.status_bar.messages = [
                    "Ln {}, Col {} ({} selected)".format(
                        editor.line, editor.column, editor.selection_length)
                ]
            else:
                self.status_bar.messages = [
                    "Ln {}, Col {}".format(editor.line, editor.column)
                ]
        else:
            self.status_bar.messages = []

    # Trait property getter/setters ------------------------------------------

    @cached_property
    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None
Ejemplo n.º 21
0
 def get_icon(self):
     return ImageResource('gauss_1d')
Ejemplo n.º 22
0
class WorkflowInfo(HasTraits):

    # -------------------
    # Required Attributes
    # -------------------

    #: Filename for the current workflow (if any)
    workflow_filename = Str()

    #: A list of the loaded plugins
    plugins = List(Plugin)

    #: The factory currently selected in the SetupPane
    selected_factory_name = Str()

    #: An error message for the entire workflow
    error_message = Str()

    # ---------------------
    # Dependent Attributes
    # ---------------------

    #: The force project logo! Stored at images/Force_Logo.png
    image = ImageResource('Force_Logo.png')

    #: Message indicating currently loaded file
    workflow_filename_message = Str()

    #: A list of plugin names
    plugin_names = List(Str)

    # -----------
    #    View
    # -----------

    traits_view = View(
        VGroup(
            horizontal_centre(
                Group(UItem('image',
                            editor=ImageEditor(scale=True,
                                               allow_upscaling=False,
                                               preserve_aspect_ratio=True)),
                      visible_when="selected_factory_name == 'Workflow'")),
            Group(UReadonly('plugin_names',
                            editor=ListStrEditor(editable=False)),
                  show_border=True,
                  label='Available Plugins',
                  visible_when="selected_factory_name not in ['KPI']"),
            Group(
                UReadonly('workflow_filename_message', editor=TextEditor()),
                show_border=True,
                label='Workflow Filename',
            ),
            Group(UReadonly('error_message', editor=TextEditor()),
                  show_border=True,
                  label='Workflow Errors',
                  visible_when="selected_factory_name == 'Workflow'"),
        ))

    # -------------------
    #      Defaults
    # -------------------

    def _plugin_names_default(self):
        return [plugin.name for plugin in self.plugins]

    def _workflow_filename_message_default(self):
        if self.workflow_filename == '':
            return 'No File Loaded'
        return 'Current File: ' + self.workflow_filename
Ejemplo n.º 23
0
 def get_icon(self):
     return ImageResource('channel_stat')
Ejemplo n.º 24
0
class FlowTask(Task):
    """
    classdocs
    """
    
    id = "edu.mit.synbio.cytoflowgui.flow_task"
    name = "Cytometry analysis"
    
    # the main workflow instance.
    model = Instance(Workflow)
        
    # the center pane
    workflow_pane = Instance(WorkflowDockPane)
    view_pane = Instance(ViewDockPane)
    help_pane = Instance(HelpDockPane)
    plot_params_pane = Instance(PlotParamsPane)
    
    # plugin lists, to setup the interface
    op_plugins = List(IOperationPlugin)
    view_plugins = List(IViewPlugin)
    
    menu_bar = SMenuBar(SMenu(TaskAction(name='Open...',
                                         method='on_open',
                                         accelerator='Ctrl+O'),
                              TaskAction(name='Save',
                                         #image='save', 
                                         method='on_save',
                                         accelerator='Ctrl+S'),
                              TaskAction(name='Save As...',
                                         method='on_save_as',
                                         accelerator='Ctrl+e'),
                              TaskAction(name='Save Plot...',
                                         method='on_export',
                                         accelerator='Ctrl+x'),
                              TaskAction(name='Export Jupyter notebook...',
                                         method='on_notebook',
                                         accelerator='Ctrl+I'),                              
#                               TaskAction(name='Preferences...',
#                                          method='on_prefs',
#                                          accelerator='Ctrl+P'),
                              id='File', name='&File'),
                        SMenu(TaskToggleGroup(),
                              id = 'View', name = '&View'),
                        SMenu(TaskAction(name = 'Online documentation...',
                                         method = 'on_docs'),
                                         TaskAction(name = 'Report a problem....',
                                         method = 'on_problem'),
                              TaskAction(name='About...',
                                         method='on_about'),
                              id="Help", name ="&Help"))
    
    tool_bars = [ SToolBar(TaskAction(method='on_new',
                                      name = "New",
                                      tooltip='New workflow',
                                      image=ImageResource('new')),
                           TaskAction(method='on_open',
                                      name = "Open",
                                      tooltip='Open a file',
                                      image=ImageResource('open')),
                           TaskAction(method='on_save',
                                      name = "Save",
                                      tooltip='Save the current file',
                                      image=ImageResource('save')),
                           TaskAction(method='on_export',
                                      name = "Save Plot",
                                      tooltip='Save the current plot',
                                      image=ImageResource('export')),
                           TaskAction(method='on_notebook',
                                       name='Notebook',
                                       tooltip="Export to an Jupyter notebook...",
                                       image=ImageResource('jupyter')),
                           TaskAction(method = "on_calibrate",
                                      name = "Calibrate FCS...",
                                      tooltip = "Calibrate FCS files",
                                      image = ImageResource('tasbe')),
                           TaskAction(method = 'on_problem',
                                      name = "Report a bug...",
                                      tooltib = "Report a bug",
                                      image = ImageResource('bug')))]
#                            TaskAction(method='on_prefs',
#                                       name = "Prefs",
#                                       tooltip='Preferences',
#                                       image=ImageResource('prefs')),
    
    # the file to save to if the user clicks "save" and has already clicked
    # "open" or "save as".
    filename = Str
        
    def initialized(self):
        if self.filename:
            self.open_file(self.filename)

        
    def activated(self):
        
        # if we're coming back from the TASBE task, re-load the saved
        # workflow
        if self.model.backup_workflow:
            self.model.workflow = self.model.backup_workflow
            self.model.backup_workflow = []
            return
        
        # else, set up a new workflow
        # add the import op
        if not self.model.workflow:
            self.add_operation(ImportPlugin().id) 
            self.model.selected = self.model.workflow[0]
                    
        self.model.modified = False
    
    def _default_layout_default(self):
        return TaskLayout(left = VSplitter(PaneItem("edu.mit.synbio.cytoflowgui.workflow_pane", width = 350),
                                           PaneItem("edu.mit.synbio.cytoflowgui.help_pane", width = 350, height = 350)),
                          right = VSplitter(PaneItem("edu.mit.synbio.cytoflowgui.view_traits_pane", width = 350),
                                            PaneItem("edu.mit.synbio.cytoflowgui.params_pane", width = 350, height = 350)),
                          top_left_corner = 'left',
                          bottom_left_corner = 'left',
                          top_right_corner = 'right',
                          bottom_right_corner = 'right')
     
    def create_central_pane(self):   
        # set the toolbar image size
        # this isn't really the right place for this, but it's the only
        # place control passes back to user code before the toolbar
        # is created.
        
        dpi = self.window.control.physicalDpiX()
        self.tool_bars[0].image_size = (int(0.4 * dpi), int(0.4 * dpi))
        return self.application.plot_pane
     
    def create_dock_panes(self):
        self.workflow_pane = WorkflowDockPane(model = self.model, 
                                              plugins = self.op_plugins,
                                              task = self)
        
        self.view_pane = ViewDockPane(model = self.model,
                                      plugins = self.view_plugins,
                                      task = self)
        
        self.help_pane = HelpDockPane(view_plugins = self.view_plugins,
                                      op_plugins = self.op_plugins,
                                      task = self)
        
        self.plot_params_pane = PlotParamsPane(model = self.model,
                                               task = self)
        
        return [self.workflow_pane, self.view_pane, self.help_pane, self.plot_params_pane]
        
    def on_new(self):
        if self.model.modified:
            ret = confirm(parent = None,
                          message = "Are you sure you want to discard the current workflow?",
                          title = "Clear workflow?")
            
            if ret != YES:
                return
            
        self.filename = ""
        self.window.title = "Cytoflow"
        
        # clear the workflow
        self.model.workflow = []
        
        # add the import op
        self.add_operation(ImportPlugin().id) 
        
        # and select the operation
        self.model.selected = self.model.workflow[0]
        
        self.model.modified = False
     
        
    def on_open(self):
        """ 
        Shows a dialog to open a file.
        """
        
        if self.model.modified:
            ret = confirm(parent = None,
                          message = "Are you sure you want to discard the current workflow?",
                          title = "Clear workflow?")
            
            if ret != YES:
                return
        
        dialog = FileDialog(parent = self.window.control, 
                            action = 'open',
                            wildcard = (FileDialog.create_wildcard("Cytoflow workflow", "*.flow") + ';' +  #@UndefinedVariable  
                                        FileDialog.create_wildcard("All files", "*"))) #@UndefinedVariable  
        if dialog.open() == OK:
            self.open_file(dialog.path)
            self.filename = dialog.path
            self.window.title = "Cytoflow - " + self.filename
            

    def open_file(self, path):
        
        try:
            new_workflow = load_yaml(path)

            # a few things to take care of when reloading.
            # we do this in the try block to catch people who
            # load valid YAML files that aren't from cytoflow.
            
            for wi_idx, wi in enumerate(new_workflow):
                
                # get wi lock
                wi.lock.acquire()
                
                # clear the wi status
                wi.status = "loading"
    
                # re-link the linked list.
                if wi_idx > 0:
                    wi.previous_wi = new_workflow[wi_idx - 1]
                
                if wi_idx < len(new_workflow) - 1:
                    wi.next_wi = new_workflow[wi_idx + 1]

        except yaml.parser.ParserError as e:
            error(None,
                  "Parser error loading {} -- is it a Cytoflow file?\n\n{}"
                  .format(path, str(e)))
            return
        except Exception as e:
            error(None,
                  "{} loading {} -- is it a Cytoflow file?\n\n{}"
                  .format(e.__class__.__name__, path, str(e)))
            return
        
        # are we just running a smoke test?
        if 'startup_test' in new_workflow[0].metadata:
            def quit_app(app):
                app.exit(force = True)
                
            from pyface.timer.api import do_after
            do_after(5*1000, quit_app, self.application)
            return
            
        # check that the FCS files are all there
        
        wi = new_workflow[0]
        assert(wi.operation.id == "edu.mit.synbio.cytoflow.operations.import")
        missing_tubes = 0
        for tube in wi.operation.tubes:
            file = pathlib.Path(tube.file)
            if not file.exists():
                missing_tubes += 1
                
        if missing_tubes == len(wi.operation.tubes):
            warning(self.window.control,
                    "Cytoflow couldn't find any of the FCS files from that "
                    "workflow.  If they've been moved, please open one FCS "
                    "file to show Cytoflow where they've been moved to.")
            
            dialog = FileDialog(parent = self.window.control, 
                                action = 'open',
                                wildcard = (FileDialog.create_wildcard("FCS files", "*.fcs *.lmd")))  # @UndefinedVariable
            
            if dialog.open() == OK:
                # find the "best" file match -- ie, the one with the longest
                # tail match
                fcs_path = pathlib.Path(dialog.path).parts
                best_path_len = -1
                                
                for tube in wi.operation.tubes:
                    tube_path = pathlib.Path(tube.file).parts
                    
                    for i in range(len(fcs_path)):
                        if list(reversed(fcs_path))[:i] == list(reversed(tube_path))[:i] and i > best_path_len:
                            best_path_len = i
                            
                if best_path_len >= 0:
                    for tube in wi.operation.tubes:
                        tube_path = pathlib.Path(tube.file).parts
                        new_path = fcs_path[:-1 * best_path_len] + tube_path[-1 * best_path_len :]
                        tube.file = str(pathlib.Path(*new_path))
                        
        elif missing_tubes > 0:
            warning(self.window.control,
                    "Cytoflow couldn't find some of the FCS files from that "
                    "workflow.  You'll need to re-load them from the Import "
                    "operation.")

        # replace the current workflow with the one we just loaded
        
        if False:  # for debugging the loading of things
            from .event_tracer import record_events 
            
            with record_events() as container:
                self.model.workflow = new_workflow
                                
            container.save_to_directory(os.getcwd()) 
        else:
            self.model.workflow = new_workflow
            self.model.modified = False
            
        for wi in self.model.workflow:
            wi.lock.release()
            
        if self.model.debug:
            self.model.run_all()
        else:
            ret = confirm(parent = None,
                          message = "Do you want to execute the workflow now?",
                          title = "Run workflow?")
            
            if ret == YES:
                self.model.run_all()

        
    def on_save(self):
        """ Save the file to the previous filename  """
        if self.filename:
            save_yaml(self.model.workflow, self.filename)
            self.model.modified = False
        else:
            self.on_save_as()
            
    def on_save_as(self):
        dialog = DefaultFileDialog(parent = self.window.control,
                                   action = 'save as', 
                                   default_suffix = "flow",
                                   wildcard = (FileDialog.create_wildcard("Cytoflow workflow", "*.flow") + ';' + #@UndefinedVariable  
                                               FileDialog.create_wildcard("All files", "*")))                    #@UndefinedVariable  
        
        if dialog.open() == OK:
            save_yaml(self.model.workflow, dialog.path)
            self.filename = dialog.path
            self.model.modified = False
            self.window.title = "Cytoflow - " + self.filename
            
    @on_trait_change('model.modified', post_init = True)
    def _on_model_modified(self, val):
        if val:
            if not self.window.title.endswith("*"):
                self.window.title += "*"
        else:
            if self.window.title.endswith("*"):
                self.window.title = self.window.title[:-1]
        

    def on_export(self):
        task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.export_task')
        self.window.activate_task(task)        


    def on_calibrate(self):
        task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.tasbe_task')
        self.window.activate_task(task)
        
            
    def on_notebook(self):
        """
        Shows a dialog to export the workflow to an Jupyter notebook
        """

        dialog = DefaultFileDialog(parent = self.window.control,
                                   action = 'save as',
                                   default_suffix = "ipynb",
                                   wildcard = (FileDialog.create_wildcard("Jupyter notebook", "*.ipynb") + ';' + #@UndefinedVariable  
                                               FileDialog.create_wildcard("All files", "*")))  # @UndefinedVariable
        if dialog.open() == OK:
            save_notebook(self.model.workflow, dialog.path)

    
    def on_prefs(self):
        pass
    
    def on_docs(self):
        webbrowser.open_new_tab("https://cytoflow.readthedocs.io/en/stable/manual.html")

    
    def on_problem(self):

        log = str(self._get_package_versions()) + "\n" + self.application.application_log.getvalue()
        
        msg = "The best way to report a problem is send an application log to " \
              "the developers.  If you click 'Yes' below, you will be given then " \
              "opportunity to save the log to a file and then file a " \
              "new issue on GitHub at " \
              "https://github.com/cytoflow/cytoflow/issues/new" 
        
        dialog = ConfirmationDialog(message = msg,
                                    informative = "Would you like to report an issue to the developers?")
                
        if dialog.open() == YES:
            dialog = DefaultFileDialog(parent = self.window.control,
                                       action = 'save as', 
                                       default_suffix = "log",
                                       wildcard = (FileDialog.create_wildcard("Log files", "*.log") + ';' + #@UndefinedVariable  
                                                   FileDialog.create_wildcard("All files", "*")))                    #@UndefinedVariable  
            
            if dialog.open() == OK:
                with open(dialog.path, 'w') as f:
                    f.write(log)
                  
                webbrowser.open_new_tab("https://github.com/cytoflow/cytoflow/issues/new")
                  
            return
    
    def _get_package_versions(self):    
        from cytoflow import __version__ as cf_version
        from fcsparser import __version__ as fcs_version
        from pandas import __version__ as pd_version
        from numpy import __version__ as np_version
        from numexpr import __version__ as nxp_version
        from bottleneck import __version__ as btl_version
        from seaborn import __version__ as sns_version
        from matplotlib import __version__ as mpl_version
        from scipy import __version__ as scipy_version
        from sklearn import __version__ as skl_version
        from statsmodels import __version__ as stats_version
        from pyface import __version__ as pyf_version
        from envisage import __version__ as env_version
        from traits import __version__ as trt_version
        from traitsui import __version__ as trt_ui_version
        from yapf import __version__ as yapf_version
        from nbformat import __version__ as nb_version
        from yaml import __version__ as yaml_version
        
        return {"python" : sys.version,
                "cytoflow" : cf_version,
                "fcsparser" : fcs_version,
                "pandas" : pd_version,
                "numpy" : np_version,
                "numexpr" : nxp_version,
                "bottleneck" : btl_version,
                "seaborn" : sns_version,
                "matplotlib" : mpl_version,
                "scipy" : scipy_version,
                "scikit-learn" : skl_version,
                "statsmodels" : stats_version,
                "pyface" : pyf_version,
                "envisage" : env_version,
                "traits" : trt_version,
                "traitsui" : trt_ui_version,
                "nbformat" : nb_version,
                "yapf" : yapf_version,
                "yaml" : yaml_version}
        
        
    def on_about(self):
        versions = self._get_package_versions()
        text = ["<b>Cytoflow {0}</b>".format(versions['cytoflow']),
                "<p>"]
        
        ver_text = ["{0} {1}".format(key, value) for key, value in versions.items()]
        
        text.extend(ver_text)
        
        text.extend(["Icons from the <a href=http://tango.freedesktop.org>Tango Desktop Project</a>",
                "<a href=https://thenounproject.com/search/?q=setup&i=14287>Settings icon</a> by Paulo Sa Ferreira from <a href=https://thenounproject.com>The Noun Project</a>",
                "<a href=https://thenounproject.com/search/?q=processing&i=849831>Processing icon</a> by Gregor Cresnar from <a href=https://thenounproject.com>The Noun Project</a>",
                "<a href=http://www.freepik.com/free-photos-vectors/background>App icon from Starline - Freepik.com</a>",
                "Cuvette image from Wikimedia Commons user <a href=http://commons.wikimedia.org/wiki/File:Hellma_Large_cone_cytometry_cell.JPG>HellmaUSA</a>"])
        
        dialog = AboutDialog(text = text,
                             parent = self.window.control,
                             title = "About",
                             image = ImageResource('cuvette'),
                             additions = text)
        dialog.open()
        
    @on_trait_change('model.selected', post_init = True)
    def _on_select_op(self, selected):
        if selected:
            self.view_pane.enabled = (selected is not None)
            self.view_pane.default_view = selected.default_view.id if selected.default_view else ""
            self.view_pane.selected_view = selected.current_view.id if selected.current_view else ""
            self.help_pane.help_id = selected.operation.id
        else:
            self.view_pane.enabled = False
            
    @on_trait_change('view_pane.selected_view', post_init = True)
    def _on_select_view(self, view_id):
        
        if not view_id:
            return
        
        # if we already have an instantiated view object, find it
        try:
            self.model.selected.current_view = next((x for x in self.model.selected.views if x.id == view_id))
        except StopIteration:
            # else make the new view
            plugin = next((x for x in self.view_plugins if x.view_id == view_id))
            view = plugin.get_view()
            self.model.selected.views.append(view)
            self.model.selected.current_view = view
            
        self.help_pane.help_id = view_id
    
    def add_operation(self, op_id):
        # first, find the matching plugin
        plugin = next((x for x in self.op_plugins if x.id == op_id))
        
        # next, get an operation
        op = plugin.get_operation()
        
        # make a new workflow item
        wi = WorkflowItem(operation = op,
                          deletable = (op_id != 'edu.mit.synbio.cytoflowgui.op_plugins.import'))
        
        # if the op has a default view, add it to the wi
        try:
            wi.default_view = op.default_view()
            wi.views.append(wi.default_view)
            wi.current_view = wi.default_view
        except AttributeError:
            pass
        
        # figure out where to add it
        if self.model.selected:
            idx = self.model.workflow.index(self.model.selected) + 1
        else:
            idx = len(self.model.workflow)
             
        # the add_remove_items handler takes care of updating the linked list
        self.model.workflow.insert(idx, wi)
        
        # and make sure to actually select the new wi
        self.model.selected = wi
Ejemplo n.º 25
0
 def get_icon(self):
     return ImageResource('kde_1d')
Ejemplo n.º 26
0
 def get_icon(self):
     return ImageResource('radviz')
Ejemplo n.º 27
0
class NodeType(HasPrivateTraits):
    """ The base class for all node types. """

    # The default image used to represent nodes that DO NOT allow children.
    DOCUMENT = ImageResource("document")

    # The default image used to represent nodes that allow children and are NOT
    # expanded.
    CLOSED_FOLDER = ImageResource("closed_folder")

    # The default image used to represent nodes that allow children and ARE
    # expanded.
    OPEN_FOLDER = ImageResource("open_folder")

    # 'NodeType' interface -------------------------------------------------

    # The node manager that the type belongs to.
    node_manager = Instance("pyface.tree.node_manager.NodeManager")

    # The image used to represent nodes that DO NOT allow children.
    image = Instance(ImageResource)

    # The image used to represent nodes that allow children and are NOT
    # expanded.
    closed_image = Instance(ImageResource)

    # The image used to represent nodes that allow children and ARE expanded.
    open_image = Instance(ImageResource)

    # The default actions/groups/menus available on nodes of this type (shown
    # on the context menu).
    actions = Any  # List

    # The default action for nodes of this type.  The default action is
    # performed when a node is activated (i.e., double-clicked).
    default_action = Instance(Action)

    # The default actions/groups/menus for creating new children within nodes
    # of this type (shown in the 'New' menu of the context menu).
    new_actions = Any  # List

    # ------------------------------------------------------------------------
    # 'NodeType' interface.
    # ------------------------------------------------------------------------

    # These methods are specific to the 'NodeType' interface ---------------

    def is_type_for(self, node):
        """ Returns True if a node is deemed to be of this type. """

        raise NotImplementedError()

    def allows_children(self, node):
        """ Does the node allow children (ie. a folder vs a file). """

        return False

    def get_actions(self, node):
        """ Returns the node-specific actions for a node. """

        return self.actions

    def get_context_menu(self, node):
        """ Returns the context menu for a node. """

        sat = Group(id="SystemActionsTop")
        nsa = Group(id="NodeSpecificActions")
        sab = Group(id="SystemActionsBottom")

        # The 'New' menu.
        new_actions = self.get_new_actions(node)
        if new_actions is not None and len(new_actions) > 0:
            sat.append(MenuManager(name="New", *new_actions))

        # Node-specific actions.
        actions = self.get_actions(node)
        if actions is not None and len(actions) > 0:
            for item in actions:
                nsa.append(item)

        # System actions (actions available on ALL nodes).
        system_actions = self.node_manager.system_actions
        if len(system_actions) > 0:
            for item in system_actions:
                sab.append(item)

        context_menu = MenuManager(sat, nsa, sab)
        context_menu.dump()

        return context_menu

    def get_copy_value(self, node):
        """ Get the value that is copied for a node.

        By default, returns the node itself.

        """

        return node

    def get_default_action(self, node):
        """ Returns the default action for a node. """

        return self.default_action

    def get_new_actions(self, node):
        """ Returns the new actions for a node. """

        return self.new_actions

    def get_paste_value(self, node):
        """ Get the value that is pasted for a node.

        By default, returns the node itself.

        """

        return node

    def get_monitor(self, node):
        """ Returns a monitor that detects changes to a node.

        Returns None by default,  which indicates that the node is not
        monitored.

        """

        return None

    # These methods are exactly the same as the 'TreeModel' interface -----#

    def has_children(self, node):
        """ Returns True if a node has children, otherwise False.

        You only need to implement this method if children are allowed for the
        node (ie. 'allows_children' returns True).

        """

        return False

    def get_children(self, node):
        """ Returns the children of a node.

        You only need to implement this method if children are allowed for the
        node.

        """

        raise NotImplementedError()

    def get_drag_value(self, node):
        """ Get the value that is dragged for a node.

        By default, returns the node itself.

        """

        return node

    def can_drop(self, node, data):
        """ Returns True if a node allows an object to be dropped onto it. """

        return False

    def drop(self, obj, data):
        """ Drops an object onto a node. """

        raise NotImplementedError()

    def get_image(self, node, selected, expanded):
        """ Returns the label image for a node. """

        if self.allows_children(node):
            if expanded:
                order = ["open_image", "closed_image", "image"]
                default = self.OPEN_FOLDER

            else:
                order = ["closed_image", "open_image", "image"]
                default = self.CLOSED_FOLDER

        else:
            order = ["image", "open_image", "closed_image"]
            default = self.DOCUMENT

        # Use the search order to look for a trait that is NOT None.
        for name in order:
            image = getattr(self, name)
            if image is not None:
                break

        # If no such trait is found then use the default image.
        else:
            image = default

        return image

    def get_selection_value(self, node):
        """ Get the value that is used when a node is selected.

        By default the selection value is the node itself.

        """

        return node

    def get_text(self, node):
        """ Returns the label text for a node. """

        return str(node)

    def can_set_text(self, node, text):
        """ Returns True if the node's label can be set. """

        return len(text.strip()) > 0

    def set_text(self, node, text):
        """ Sets the label text for a node. """

        pass

    def is_collapsible(self, node):
        """ Returns True if the node is collapsible, otherwise False. """

        return True

    def is_draggable(self, node):
        """ Returns True if the node is draggablee, otherwise False. """

        return True

    def can_rename(self, node):
        """ Returns True if the node can be renamed, otherwise False. """

        return False

    def is_editable(self, node):
        """ Returns True if the node is editable, otherwise False.

        If the node is editable, its text can be set via the UI.

        DEPRECATED: Use 'can_rename'.

        """

        return self.can_rename(node)

    def is_expandable(self, node):
        """ Returns True if the node is expandanble, otherwise False. """

        return True
Ejemplo n.º 28
0
 def get_icon(self):
     return ImageResource('stats_2d')
Ejemplo n.º 29
0
class FlowTask(Task):
    """
    classdocs
    """
    
    id = "edu.mit.synbio.cytoflowgui.flow_task"
    name = "Cytometry analysis"
    
    # the main workflow instance.
    model = Instance(Workflow)
        
    # the center pane
    workflow_pane = Instance(WorkflowDockPane)
    view_pane = Instance(ViewDockPane)
    help_pane = Instance(HelpDockPane)
    plot_params_pane = Instance(PlotParamsPane)
    
    # plugin lists, to setup the interface
    op_plugins = List(IOperationPlugin)
    view_plugins = List(IViewPlugin)
    
    menu_bar = SMenuBar(SMenu(TaskAction(name='Open...',
                                         method='on_open',
                                         accelerator='Ctrl+O'),
                              TaskAction(name='Save',
                                         #image='save', 
                                         method='on_save',
                                         accelerator='Ctrl+S'),
                              TaskAction(name='Save As...',
                                         method='on_save_as',
                                         accelerator='Ctrl+e'),
                              TaskAction(name='Save Plot...',
                                         method='on_export',
                                         accelerator='Ctrl+x'),
                              TaskAction(name='Export Jupyter notebook...',
                                         method='on_notebook',
                                         accelerator='Ctrl+I'),                              
#                               TaskAction(name='Preferences...',
#                                          method='on_prefs',
#                                          accelerator='Ctrl+P'),
                              id='File', name='&File'),
                        SMenu(TaskToggleGroup(),
#                               TaskWindowToggleGroup(),
                              id = 'View', name = '&View'),
                        SMenu(TaskAction(name = 'Report a problem....',
                                         method = 'on_problem'),
                              TaskAction(name='About...',
                                         method='on_about'),
                              id="Help", name ="&Help"))
    
    tool_bars = [ SToolBar(TaskAction(method='on_new',
                                      name = "New",
                                      tooltip='New workflow',
                                      image=ImageResource('new')),
                           TaskAction(method='on_open',
                                      name = "Open",
                                      tooltip='Open a file',
                                      image=ImageResource('open')),
                           TaskAction(method='on_save',
                                      name = "Save",
                                      tooltip='Save the current file',
                                      image=ImageResource('save')),
                           TaskAction(method='on_export',
                                      name = "Save Plot",
                                      tooltip='Save the current plot',
                                      image=ImageResource('export')),
                           TaskAction(method='on_notebook',
                                       name='Notebook',
                                       tooltip="Export to an Jupyter notebook...",
                                       image=ImageResource('ipython')),
                           TaskAction(method = "on_calibrate",
                                      name = "Calibrate FCS...",
                                      tooltip = "Calibrate FCS files",
                                      image = ImageResource('tasbe')),
                           TaskAction(method = 'on_problem',
                                      name = "Report a bug...",
                                      tooltib = "Report a bug",
                                      image = ImageResource('bug')),
#                            TaskAction(method='on_prefs',
#                                       name = "Prefs",
#                                       tooltip='Preferences',
#                                       image=ImageResource('prefs')),
                           image_size = (32, 32))]
    
    # the file to save to if the user clicks "save" and has already clicked
    # "open" or "save as".
    filename = Unicode
        
    def activated(self):
        
        # if we're coming back from the TASBE task, re-load the saved
        # workflow
        if self.model.backup_workflow:
            self.model.workflow = self.model.backup_workflow
            self.model.backup_workflow = []
            return
        
        # else, set up a new workflow
        
        # add the import op
        if not self.model.workflow:
            self.add_operation(ImportPlugin().id) 
            self.model.selected = self.model.workflow[0]
        
        # if we're debugging, add a few data bits
        if self.model.debug:
            from cytoflow import Tube
                        
            import_op = self.model.workflow[0].operation
            import_op.conditions = {"Dox" : "float", "Well" : "category"}
         
            tube1 = Tube(file = "../cytoflow/tests/data/Plate01/CFP_Well_A4.fcs",
                         conditions = {"Dox" : 0.0, "Well" : 'A'})
         
            tube2 = Tube(file = "../cytoflow/tests/data/Plate01/RFP_Well_A3.fcs",
                         conditions = {"Dox" : 10.0, "Well" : 'A'})
             
            tube3 = Tube(file = "../cytoflow/tests/data/Plate01/CFP_Well_B4.fcs",
                         conditions = {"Dox" : 0.0, "Well" : 'B'})
         
            tube4 = Tube(file = "../cytoflow/tests/data/Plate01/RFP_Well_A6.fcs",
                         conditions = {"Dox" : 10.0, "Well" : 'B'})
         
            import_op.tubes = [tube1, tube2, tube3, tube4]
            
#             from cytoflowgui.op_plugins import ChannelStatisticPlugin

#             self.add_operation(ChannelStatisticPlugin().id)
#             stat_op = self.model.workflow[1].operation
#             stat_op.name = "Test"
#             stat_op.channel = "Y2-A"
#             stat_op.statistic_name = "Geom.Mean"
#             stat_op.by = ["Dox", "Well"]
#             self.model.selected = self.model.workflow[1]
                    
        self.model.modified = False
    
    def _default_layout_default(self):
        return TaskLayout(left = VSplitter(PaneItem("edu.mit.synbio.cytoflowgui.workflow_pane"),
                                           PaneItem("edu.mit.synbio.cytoflowgui.help_pane")),
                          right = VSplitter(PaneItem("edu.mit.synbio.cytoflowgui.view_traits_pane"),
                                            PaneItem("edu.mit.synbio.cytoflowgui.params_pane")),
                          top_left_corner = 'left',
                          bottom_left_corner = 'left',
                          top_right_corner = 'right',
                          bottom_right_corner = 'right')
     
    def create_central_pane(self):       
        return self.application.plot_pane
     
    def create_dock_panes(self):
        self.workflow_pane = WorkflowDockPane(model = self.model, 
                                              plugins = self.op_plugins,
                                              task = self)
        
        self.view_pane = ViewDockPane(model = self.model,
                                      plugins = self.view_plugins,
                                      task = self)
        
        self.help_pane = HelpDockPane(view_plugins = self.view_plugins,
                                      op_plugins = self.op_plugins,
                                      task = self)
        
        self.plot_params_pane = PlotParamsPane(model = self.model,
                                               task = self)
        
        return [self.workflow_pane, self.view_pane, self.help_pane, self.plot_params_pane]
        
    def on_new(self):
        if self.model.modified:
            ret = confirm(parent = None,
                          message = "Are you sure you want to discard the current workflow?",
                          title = "Clear workflow?")
            
            if ret != YES:
                return
            
        self.filename = ""
        self.window.title = "Cytoflow"
        
        # clear the workflow
        self.model.workflow = []
        
        # add the import op
        self.add_operation(ImportPlugin().id) 
        
        # and select the operation
        self.model.selected = self.model.workflow[0]
        
        self.model.modified = False
     
        
    def on_open(self):
        """ 
        Shows a dialog to open a file.
        """
        
        if self.model.modified:
            ret = confirm(parent = None,
                          message = "Are you sure you want to discard the current workflow?",
                          title = "Clear workflow?")
            
            if ret != YES:
                return
        
        dialog = FileDialog(parent = self.window.control, 
                            action = 'open',
                            wildcard = (FileDialog.create_wildcard("Cytoflow workflow", "*.flow") + ';' +  #@UndefinedVariable  
                                        FileDialog.create_wildcard("All files", "*"))) #@UndefinedVariable  
        if dialog.open() == OK:
            self.open_file(dialog.path)
            self.filename = dialog.path
            self.window.title = "Cytoflow - " + self.filename
            

    def open_file(self, path):
        
        new_workflow = load_yaml(path)
        
        # a few things to take care of when reloading
        for wi_idx, wi in enumerate(new_workflow):
            
            # get wi lock
            wi.lock.acquire()
            
            # clear the wi status
            wi.status = "loading"

            # re-link the linked list.
            if wi_idx > 0:
                wi.previous_wi = new_workflow[wi_idx - 1]
            
            if wi_idx < len(new_workflow) - 1:
                wi.next_wi = new_workflow[wi_idx + 1]


        # replace the current workflow with the one we just loaded
        
        if False:  # for debugging the loading of things
            from .event_tracer import record_events 
            
            with record_events() as container:
                self.model.workflow = new_workflow
                                
            container.save_to_directory(os.getcwd()) 
        else:
            self.model.workflow = new_workflow
            self.model.modified = False
            
        for wi in self.model.workflow:
            wi.lock.release()

        
    def on_save(self):
        """ Save the file to the previous filename  """
        if self.filename:
            save_yaml(self.model.workflow, self.filename)
            self.model.modified = False
        else:
            self.on_save_as()
            
    def on_save_as(self):
        dialog = DefaultFileDialog(parent = self.window.control,
                                   action = 'save as', 
                                   default_suffix = "flow",
                                   wildcard = (FileDialog.create_wildcard("Cytoflow workflow", "*.flow") + ';' + #@UndefinedVariable  
                                               FileDialog.create_wildcard("All files", "*")))                    #@UndefinedVariable  
        
        if dialog.open() == OK:
            save_yaml(self.model.workflow, dialog.path)
            self.filename = dialog.path
            self.model.modified = False
            self.window.title = "Cytoflow - " + self.filename
            
    @on_trait_change('model.modified', post_init = True)
    def _on_model_modified(self, val):
        if val:
            if not self.window.title.endswith("*"):
                self.window.title += "*"
        else:
            if self.window.title.endswith("*"):
                self.window.title = self.window.title[:-1]
        

    def on_export(self):
        task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.export_task')
        self.window.activate_task(task)        


    def on_calibrate(self):
        task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.tasbe_task')
        self.window.activate_task(task)
        
            
    def on_notebook(self):
        """
        Shows a dialog to export the workflow to an Jupyter notebook
        """

        dialog = FileDialog(parent = self.window.control,
                            action = 'save as',
                            default_suffix = "ipynb",
                            wildcard = (FileDialog.create_wildcard("Jupyter notebook", "*.ipynb") + ';' + #@UndefinedVariable  
                                        FileDialog.create_wildcard("All files", "*")))  # @UndefinedVariable
        if dialog.open() == OK:
            save_notebook(self.model.workflow, dialog.path)

    
    def on_prefs(self):
        pass
    
    def on_problem(self):

        log = str(self._get_package_versions()) + "\n" + self.application.application_log.getvalue()
        
        msg = "The best way to report a problem is send an application log to " \
              "the developers.  You can do so by either sending us an email " \
              "with the log in it, or saving the log to a file and filing a " \
              "new issue on GitHub at " \
              "https://github.com/bpteague/cytoflow/issues/new" 
        
        dialog = ConfirmationDialog(message = msg,
                                    informative = "Which would you like to do?",
                                    yes_label = "Send an email...",
                                    no_label = "Save to a file...")
                
        if dialog.open() == NO:
            dialog = DefaultFileDialog(parent = self.window.control,
                                       action = 'save as', 
                                       default_suffix = "log",
                                       wildcard = (FileDialog.create_wildcard("Log files", "*.log") + ';' + #@UndefinedVariable  
                                                   FileDialog.create_wildcard("All files", "*")))                    #@UndefinedVariable  
            
            if dialog.open() == OK:
                with open(dialog.path, 'w') as f:
                    f.write(log)
                  
                webbrowser.open_new_tab("https://github.com/bpteague/cytoflow/issues/new")
                  
            return
        
        information(None, "I'll now try to open your email client and create a "
                    "new message to the developer.  Debugging logs are "
                    "attached.  Please fill out the template bug report and " 
                    "send -- thank you for reporting a bug!")

        log = self.application.application_log.getvalue()
        
        versions = ["{0} {1}".format(key, value) for key, value in self._get_package_versions().items()]

        body = """
Thank you for your bug report!  Please fill out the following template.

PLATFORM (Mac, PC, Linux, other):

OPERATING SYSTEM (eg OSX 10.7, Windows 8.1):

SEVERITY (Critical? Major? Minor? Enhancement?):

DESCRIPTION:
  - What were you trying to do?
  - What happened?
  - What did you expect to happen?
  
PACKAGE VERSIONS: {0}

DEBUG LOG: {1}
""".format(versions, log)

        mailto("*****@*****.**", 
               subject = "Cytoflow bug report",
               body = body)
    
    def _get_package_versions(self):
    
        import sys
        from cytoflow import __version__ as cf_version
        from fcsparser import __version__ as fcs_version
        from pandas import __version__ as pd_version
        from numpy import __version__ as np_version
        from numexpr import __version__ as nxp_version
        from bottleneck import __version__ as btl_version
        from seaborn import __version__ as sns_version
        from matplotlib import __version__ as mpl_version
        from scipy import __version__ as scipy_version
        from sklearn import __version__ as skl_version
        from statsmodels import __version__ as stats_version
        from pyface import __version__ as pyf_version
        from envisage import __version__ as env_version
        from traits import __version__ as trt_version
        from traitsui import __version__ as trt_ui_version
        from yapf import __version__ as yapf_version
        from nbformat import __version__ as nb_version
        from yaml import __version__ as yaml_version
        
        return {"python" : sys.version,
                "cytoflow" : cf_version,
                "fcsparser" : fcs_version,
                "pandas" : pd_version,
                "numpy" : np_version,
                "numexpr" : nxp_version,
                "bottleneck" : btl_version,
                "seaborn" : sns_version,
                "matplotlib" : mpl_version,
                "scipy" : scipy_version,
                "scikit-learn" : skl_version,
                "statsmodels" : stats_version,
                "pyface" : pyf_version,
                "envisage" : env_version,
                "traits" : trt_version,
                "traitsui" : trt_ui_version,
                "nbformat" : nb_version,
                "yapf" : yapf_version,
                "yaml" : yaml_version}
        
        
    def on_about(self):
        versions = self._get_package_versions()
        text = ["<b>Cytoflow {0}</b>".format(versions['cytoflow']),
                "<p>"]
        
        ver_text = ["{0} {1}".format(key, value) for key, value in versions.items()]
        
        text.extend(ver_text)
        
        text.extend(["Icons from the <a href=http://tango.freedesktop.org>Tango Desktop Project</a>",
                "<a href=https://thenounproject.com/search/?q=setup&i=14287>Settings icon</a> by Paulo Sa Ferreira from <a href=https://thenounproject.com>The Noun Project</a>",
                "<a href=http://www.freepik.com/free-photos-vectors/background>App icon from Starline - Freepik.com</a>",
                "Cuvette image from Wikimedia Commons user <a href=http://commons.wikimedia.org/wiki/File:Hellma_Large_cone_cytometry_cell.JPG>HellmaUSA</a>"])
        
        dialog = AboutDialog(text = text,
                             parent = self.window.control,
                             title = "About",
                             image = ImageResource('cuvette'),
                             additions = text)
        dialog.open()
        
    @on_trait_change('model.selected', post_init = True)
    def _on_select_op(self, selected):
        if selected:
            self.view_pane.enabled = (selected is not None)
            self.view_pane.default_view = selected.default_view.id if selected.default_view else ""
            self.view_pane.selected_view = selected.current_view.id if selected.current_view else ""
            self.help_pane.help_id = selected.operation.id
        else:
            self.view_pane.enabled = False
            
    @on_trait_change('view_pane.selected_view', post_init = True)
    def _on_select_view(self, view_id):
        
        if not view_id:
            return
        
        # if we already have an instantiated view object, find it
        try:
            self.model.selected.current_view = next((x for x in self.model.selected.views if x.id == view_id))
        except StopIteration:
            # else make the new view
            plugin = next((x for x in self.view_plugins if x.view_id == view_id))
            view = plugin.get_view()
            self.model.selected.views.append(view)
            self.model.selected.current_view = view
            
        self.help_pane.help_id = view_id
    
    def add_operation(self, op_id):
        # first, find the matching plugin
        plugin = next((x for x in self.op_plugins if x.id == op_id))
        
        # next, get an operation
        op = plugin.get_operation()
        
        # make a new workflow item
        wi = WorkflowItem(operation = op,
                          deletable = (op_id != 'edu.mit.synbio.cytoflowgui.op_plugins.import'))
        
        # if the op has a default view, add it to the wi
        try:
            wi.default_view = op.default_view()
            wi.views.append(wi.default_view)
            wi.current_view = wi.default_view
        except AttributeError:
            pass
        
        # figure out where to add it
        if self.model.selected:
            idx = self.model.workflow.index(self.model.selected) + 1
        else:
            idx = len(self.model.workflow)
             
        # the add_remove_items handler takes care of updating the linked list
        self.model.workflow.insert(idx, wi)
        
        # and make sure to actually select the new wi
        self.model.selected = wi
Ejemplo n.º 30
0
class ExampleTask(Task):
    """ A simple task for opening a blank editor.
    """

    # Task interface -------------------------------------------------------

    id = "example.example_task"
    name = "Multi-Tab Editor"

    active_editor = Property(Instance(IEditor),
                             observe="editor_area.active_editor")

    editor_area = Instance(IEditorAreaPane)

    tool_bars = [
        SToolBar(
            TaskAction(
                method="new",
                tooltip="New file",
                image=ImageResource("document_new"),
            ),
            image_size=(32, 32),
        )
    ]

    # ------------------------------------------------------------------------
    # 'Task' interface.
    # ------------------------------------------------------------------------

    def _menu_bar_default(self):
        return SMenuBar(
            SMenu(
                TaskAction(name="New", method="new", accelerator="Ctrl+N"),
                id="File",
                name="&File",
            ),
            SMenu(
                DockPaneToggleGroup(),
                TaskToggleGroup(),
                id="View",
                name="&View",
            ),
        )

    def create_central_pane(self):
        """ Create the central pane: the script editor.
        """
        self.editor_area = EditorAreaPane()
        return self.editor_area

    # ------------------------------------------------------------------------
    # 'ExampleTask' interface.
    # ------------------------------------------------------------------------

    def new(self):
        """ Opens a new empty window
        """
        editor = Editor()
        self.editor_area.add_editor(editor)
        self.editor_area.activate_editor(editor)
        self.activated()

    # Trait property getter/setters ----------------------------------------

    def _get_active_editor(self):
        if self.editor_area is not None:
            return self.editor_area.active_editor
        return None