def _menu_bar_default(self): """A menu bar with functions relevant to the Setup task. """ menu_bar = SMenuBar(SMenu(TaskToggleGroup(), id='File', name='&File'), SMenu(id='Edit', name='&Edit'), SMenu(TaskToggleGroup(), id='View', name='&View')) return menu_bar
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=Tabbed(PaneItem('steps.first_pane'), PaneItem('steps.second_pane'), PaneItem('steps.third_pane')))
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 _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", ), )
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"), ), ) )
def get_actions_Menu_View_TaskGroup(self): return [ DocumentationOnlyAction( name="Pane Visibility:", description= "Toggles whether or not the named extra pane is shown or hidden in the current window." ), DockPaneToggleGroup(separator=False), DocumentationOnlyAction( name="Current Task:", description= "Changes the view in the entire window to a new editing task. The files in the current task are not lost, it's just a way to edit different types of files while using the same top level window on the desktop." ), TaskToggleGroup(separator=False), ]
class PikosTask(Task): #### 'Task' interface ##################################################### id = 'pikos.live.pikos_task' name = 'Pikos Live Plotting' menu_bar = SMenuBar(SMenu(id='File', name='&File'), SMenu(id='Edit', name='&Edit'), SMenu(TaskToggleGroup(), id='View', name='&View')) #### 'PikosTask' interface ################################################ ########################################################################### # 'Task' interface. ########################################################################### def create_central_pane(self): """ Create a plot pane with a list of models. Keep track of which model is active so that dock panes can introspect it. """ pane = PikosTaskPane() return pane
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
class ExportTask(Task): """ classdocs """ id = "edu.mit.synbio.cytoflowgui.export_task" name = "Export figure" menu_bar = SMenuBar(SMenu(TaskToggleGroup(), id='View', name='&View')) # the main workflow instance. model = Instance(Workflow) params_pane = Instance(TraitsDockPane) export_pane = Instance(TraitsDockPane) def _default_layout_default(self): return TaskLayout(right=VSplitter( PaneItem("edu.mit.synbio.cytoflowgui.plot_params_pane", width=350), PaneItem("edu.mit.synbio.cytoflowgui.export_pane", width=350))) def create_central_pane(self): return self.application.plot_pane def create_dock_panes(self): self.params_pane = PlotParamsPane(model=self.model, task=self) self.export_pane = ExportPane(task=self) return [self.params_pane, self.export_pane] @on_trait_change('export_pane:do_exit', post_init=True) def activate_cytoflow_task(self): task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.flow_task') self.window.activate_task(task) @on_trait_change('export_pane:do_export', post_init=True) def on_export(self): """ Shows a dialog to export a file """ f = "" filetypes_groups = self.application.plot_pane.canvas.get_supported_filetypes_grouped( ) filename_exts = [] for name, ext in filetypes_groups.items(): if f: f += ";" f += FileDialog.create_wildcard(name, " ".join(["*." + e for e in ext ])) #@UndefinedVariable filename_exts.append(ext) dialog = FileDialog(parent=self.window.control, action='save as', wildcard=f) if dialog.open() == OK: filetypes = list(self.application.plot_pane.canvas. get_supported_filetypes().keys()) if not [ ext for ext in ["." + ext for ext in filetypes] if dialog.path.endswith(ext) ]: selected_exts = filename_exts[dialog.wildcard_index] ext = sorted(selected_exts, key=len)[0] dialog.path += "." dialog.path += ext if (self.export_pane.width * self.export_pane.dpi > 2**16 or \ self.export_pane.height * self.export_pane.dpi > 2**16 or \ self.export_pane.width * self.export_pane.height * self.export_pane.dpi ** 2 > 2 ** 30) and \ pathlib.Path(dialog.path).suffix in ['png', 'pgf', 'raw', 'rgba', 'jpg', 'jpeg', 'bmp', 'pcx', 'tif', 'tiff', 'xpm']: error( None, "Can't export raster images with a height or width larger than 65535 pixels, " "or a total image size of greater than 2**30 pixels. " "Decrease your image size or DPI, or use a vector format (like PDF or SVG)." ) return self.application.plot_pane.export(dialog.path, width=self.export_pane.width, height=self.export_pane.height, dpi=self.export_pane.dpi)
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
class TASBETask(Task): """ classdocs """ id = "edu.mit.synbio.cytoflowgui.tasbe_task" name = "TASBE calibration" menu_bar = SMenuBar(SMenu(TaskToggleGroup(), id = 'View', name = '&View')) # the main workflow instance. model = Instance(Workflow) op = Instance(IOperation) calibration_pane = Instance(CalibrationPane) help_pane = Instance(HelpDockPane) _cached_help = HTML def activated(self): self.model.backup_workflow = self.model.workflow self.model.workflow = [] self.model.modified = False # add the op self.op = TasbeCalibrationOp() # make a new workflow item wi = WorkflowItem(operation = self.op, deletable = False) wi.default_view = self.op.default_view() wi.views.append(wi.default_view) wi.current_view = wi.default_view self.model.workflow.append(wi) self.model.selected = wi self.help_pane.html = self.op.get_help() def _default_layout_default(self): return TaskLayout(left = PaneItem("edu.mit.synbio.cytoflowgui.calibration_pane", width = 350), right = PaneItem("edu.mit.synbio.cytoflowgui.help_pane", width = 350)) def create_central_pane(self): return self.application.plot_pane def create_dock_panes(self): self.calibration_pane = CalibrationPane(model = self.model, task = self) self.help_pane = HelpDockPane(task = self) return [self.calibration_pane, self.help_pane] @on_trait_change('op:do_exit', post_init = True) def activate_cytoflow_task(self): task = next(x for x in self.window.tasks if x.id == 'edu.mit.synbio.cytoflowgui.flow_task') self.window.activate_task(task)
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), depends_on='editor_area.active_editor') editor_area = Instance(IEditorAreaPane) 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(top=Tabbed(PaneItem('steps.first_pane'), PaneItem('steps.second_pane'), PaneItem('steps.third_pane'))) 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. """ return [FirstPane(), SecondPane(), ThirdPane()] ########################################################################### # '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
class Visualize2dTask(Task): """ A task for visualizing attractors in 2D. """ #### 'Task' interface ##################################################### id = 'example.attractors.task_2d' name = '2D Visualization' menu_bar = SMenuBar(SMenu(id='File', name='&File'), SMenu(id='Edit', name='&Edit'), SMenu(TaskToggleGroup(), id='View', name='&View')) #### 'Visualize2dTask' interface ########################################## # The attractor model that is currently active (visible in the center pane). active_model = Any # The list of available attractor models. models = List ########################################################################### # 'Task' interface. ########################################################################### def create_central_pane(self): """ Create a plot pane with a list of models. Keep track of which model is active so that dock panes can introspect it. """ pane = Plot2dPane(models=self.models) self.active_model = pane.active_model pane.on_trait_change(self._update_active_model, 'active_model') return pane def create_dock_panes(self): return [ ModelConfigPane(model=self.active_model), ModelHelpPane(model=self.active_model) ] ########################################################################### # Protected interface. ########################################################################### #### Trait initializers ################################################### def _default_layout_default(self): return TaskLayout( left=Tabbed(PaneItem('example.attractors.model_config_pane'), PaneItem('example.attractors.model_help_pane'))) def _models_default(self): from model.henon import Henon from model.lorenz import Lorenz from model.rossler import Rossler return [Henon(), Lorenz(), Rossler()] #### Trait change handlers ################################################ def _update_active_model(self): self.active_model = self.window.central_pane.active_model for dock_pane in self.window.dock_panes: dock_pane.model = self.active_model
class Visualize3dTask(Task): """ A task for visualizing attractors in 3D. """ #### 'Task' interface ##################################################### id = "example.attractors.task_3d" name = "3D Visualization" menu_bar = SMenuBar( SMenu(id="File", name="&File"), SMenu(id="Edit", name="&Edit"), SMenu(TaskToggleGroup(), id="View", name="&View"), ) #### 'Visualize3dTask' interface ########################################## # The attractor model that is currently active (visible in the center # pane). active_model = Any # The list of available attractor models. models = List ########################################################################### # 'Task' interface. ########################################################################### def create_central_pane(self): """ Create a plot pane with a list of models. Keep track of which model is active so that dock panes can introspect it. """ pane = Plot3dPane(models=self.models) self.active_model = pane.active_model pane.on_trait_change(self._update_active_model, "active_model") return pane def create_dock_panes(self): return [ ModelConfigPane(model=self.active_model), ModelHelpPane(model=self.active_model), ] ########################################################################### # Protected interface. ########################################################################### #### Trait initializers ################################################### def _default_layout_default(self): return TaskLayout(left=Tabbed( PaneItem("example.attractors.model_config_pane"), PaneItem("example.attractors.model_help_pane"), )) def _models_default(self): from attractors.model.lorenz import Lorenz from attractors.model.rossler import Rossler return [Lorenz(), Rossler()] #### Trait change handlers ################################################ def _update_active_model(self): self.active_model = self.window.central_pane.active_model for dock_pane in self.window.dock_panes: dock_pane.model = self.active_model
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) menu_bar = SMenuBar( SMenu( TaskAction(name="New", method="new", accelerator="Ctrl+N"), TaskAction(name="Add Task", method="add_task", accelerator="Ctrl+A"), TaskAction(name="Remove Task", method="remove_task", accelerator="Ctrl+R"), 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(top=VSplitter( HSplitter(PaneItem("steps.pane1"), PaneItem("steps.pane2")))) 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. """ return [Pane1(), Pane2()] # ------------------------------------------------------------------------ # '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() def add_task(self): """ Opens a new empty window """ task3 = ThirdTask() self.window.add_task(task3) self.window.activate_task(task3) def remove_task(self): """ Opens a new empty window """ task = self.window.tasks[0] window = self.window window.remove_task(self) window.activate_task(task) # Trait property getter/setters ---------------------------------------- def _get_active_editor(self): if self.editor_area is not None: return self.editor_area.active_editor return None
class SkeletonTask(Task): """ A simple task for opening a blank editor. """ #### Task interface ####################################################### id = 'omnivore.framework.text_edit_task' name = 'Skeleton' active_editor = Property(Instance(IEditor), depends_on='editor_area.active_editor') editor_area = Instance(IEditorAreaPane) menu_bar = SMenuBar( SMenu(TaskAction(name='New', method='new', accelerator='Ctrl+N'), id='File', name='&File'), SMenu(id='Edit', name='&Edit'), 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( PaneItem('text_edit.pane1'), HSplitter( PaneItem('text_edit.pane2'), PaneItem('text_edit.pane3'), ), )) def create_central_pane(self): """ Create the central pane: the text 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. """ return [SkeletonPane1(), SkeletonPane2(), SkeletonPane3()] ########################################################################### # '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