def save_pipeline(self, workspace, outf=None): """Save the pipeline in Batch_data.mat Save the pickled image_set_list state in a setting and put this module in batch mode. if outf is not None, it is used as a file object destination. """ if outf is None: if self.wants_default_output_directory.value: path = cpprefs.get_default_output_directory() else: path = cpprefs.get_absolute_path( self.custom_output_directory.value) h5_path = os.path.join(path, F_BATCH_DATA_H5) else: h5_path = outf image_set_list = workspace.image_set_list pipeline = workspace.pipeline m = cpmeas.Measurements(copy=workspace.measurements, filename=h5_path) try: assert isinstance(pipeline, cpp.Pipeline) assert isinstance(m, cpmeas.Measurements) orig_pipeline = pipeline pipeline = pipeline.copy() # this use of workspace.frame is okay, since we're called from # prepare_run which happens in the main wx thread. target_workspace = cpw.Workspace(pipeline, None, None, None, m, image_set_list, workspace.frame) pipeline.prepare_to_create_batch(target_workspace, self.alter_path) bizarro_self = pipeline.module(self.module_num) bizarro_self.revision.value = int( re.sub(r"\.|rc\d{1}", "", cellprofiler.__version__)) if self.wants_default_output_directory: bizarro_self.custom_output_directory.value = self.alter_path( cpprefs.get_default_output_directory()) bizarro_self.default_image_directory.value = self.alter_path( cpprefs.get_default_image_directory()) bizarro_self.batch_mode.value = True pipeline.write_pipeline_measurement(m) orig_pipeline.write_pipeline_measurement(m, user_pipeline=True) # # Write the path mappings to the batch measurements # m.write_path_mappings([(mapping.local_directory.value, mapping.remote_directory.value) for mapping in self.mappings]) return h5_path finally: m.close()
def create_settings(self): """Create the module settings and name the module""" self.wants_default_output_directory = cps.Binary( "Store batch files in default output folder?", True, doc="""\ Select "*Yes*" to store batch files in the Default Output folder. Select "*No*" to enter the path to the folder that will be used to store these files. The Default Output folder can be set by clicking the "View output settings" button in the main CP window, or in CellProfiler Preferences. """ % globals(), ) self.custom_output_directory = cps.Text( "Output folder path", cpprefs.get_default_output_directory(), doc= "Enter the path to the output folder. (Used only if not using the default output folder)", ) # Worded this way not because I am windows-centric but because it's # easier than listing every other OS in the universe except for VMS self.remote_host_is_windows = cps.Binary( "Are the cluster computers running Windows?", False, doc="""\ Select "*Yes*" if the cluster computers are running one of the Microsoft Windows operating systems. In this case, **CreateBatchFiles** will modify all paths to use the Windows file separator (backslash \\\\ ). Select "*No*" for **CreateBatchFiles** to modify all paths to use the Unix or Macintosh file separator (slash / ).""" % globals(), ) self.batch_mode = cps.Binary("Hidden: in batch mode", False) self.distributed_mode = cps.Binary("Hidden: in distributed mode", False) self.default_image_directory = cps.Setting( "Hidden: default input folder at time of save", cpprefs.get_default_image_directory(), ) self.revision = cps.Integer("Hidden: revision number", 0) self.from_old_matlab = cps.Binary("Hidden: from old matlab", False) self.acknowledge_old_matlab = cps.DoSomething( "Could not update CP1.0 pipeline to be compatible with CP2.0. See module notes.", "OK", self.clear_old_matlab, ) self.mappings = [] self.add_mapping() self.add_mapping_button = cps.DoSomething( "", "Add another path mapping", self.add_mapping, doc="""\ Use this option if another path must be mapped because there is a difference between how the local computer sees a folder location vs. how the cluster computer sees the folder location.""", )
def __init__(self, parent_sizer, panel, progress_panel, status_panel): self.__panel = panel self.__parent_sizer = parent_sizer panel.AutoLayout = True panel.SetSizer(wx.BoxSizer(wx.VERTICAL)) static_box_sizer = wx.BoxSizer(wx.VERTICAL) panel.Sizer.Add(static_box_sizer, 1, wx.EXPAND) self.__sizer = static_box_sizer self.__image_folder_panel = wx.Panel(panel) self.__image_folder_panel.SetAutoLayout(True) self.__image_edit_box = self.__make_folder_panel( self.__image_folder_panel, get_default_image_directory(), lambda: get_recent_files(DEFAULT_IMAGE_DIRECTORY), "Default Input Folder", DEFAULT_IMAGE_FOLDER_HELP, [ set_default_image_directory, self.__notify_pipeline_list_view_directory_change, ], refresh_action=self.refresh_input_directory, ) self.__output_folder_panel = wx.Panel(panel) self.__output_folder_panel.SetAutoLayout(True) self.__output_edit_box = self.__make_folder_panel( self.__output_folder_panel, get_default_output_directory(), lambda: get_recent_files(DEFAULT_OUTPUT_DIRECTORY), "Default Output Folder", DEFAULT_OUTPUT_FOLDER_HELP, [ set_default_output_directory, self.__notify_pipeline_list_view_directory_change, ], ) self.__odds_and_ends_panel = wx.Panel(panel) self.__odds_and_ends_panel.SetAutoLayout(True) self.__make_odds_and_ends_panel() self.__status_panel = status_panel status_panel.Sizer = wx.BoxSizer() self.__status_text = wx.StaticText(status_panel, style=wx.SUNKEN_BORDER, label=WELCOME_MESSAGE) status_panel.Sizer.Add(self.__status_text, 1, wx.EXPAND) self.__progress_panel = progress_panel self.__progress_panel.AutoLayout = True self.__make_progress_panel() self.__sizer.AddMany([ (self.__image_folder_panel, 0, wx.EXPAND | wx.ALL, 1), (self.__output_folder_panel, 0, wx.EXPAND | wx.ALL, 1), (self.__odds_and_ends_panel, 0, wx.EXPAND | wx.ALL, 1), ]) self.show_status_text() self.__errors = set() self.__pipeline_list_view = None self.__progress_watcher = None
def save_default_folders_to_measurements(self): from ..constants.pipeline import M_DEFAULT_INPUT_FOLDER from ..constants.pipeline import M_DEFAULT_OUTPUT_FOLDER from cellprofiler_core.preferences import get_default_image_directory from cellprofiler_core.preferences import get_default_output_directory self.measurements.add_experiment_measurement( M_DEFAULT_INPUT_FOLDER, get_default_image_directory()) self.measurements.add_experiment_measurement( M_DEFAULT_OUTPUT_FOLDER, get_default_output_directory())
def __on_preferences_output_directory_event(self, event): old_selection = self.__output_edit_box.GetSelection() if self.__output_edit_box.GetValue() != get_default_output_directory(): self.__output_edit_box.SetValue(get_default_output_directory())
def run(self, workspace): default_output_directory = get_default_output_directory() tag = "runimagejmacro_" + str(random.randint(100000, 999999)) tempdir = os.path.join(default_output_directory, tag) os.makedirs(tempdir, exist_ok=True) try: for image_group in self.image_groups_in: image = workspace.image_set.get_image( image_group.image_name.value) image_pixels = image.pixel_data skimage.io.imsave( os.path.join(tempdir, image_group.output_filename.value), image_pixels) if self.executable_file.value[-4:] == ".app": executable = os.path.join( default_output_directory, self.executable_directory.value.split("|")[1], self.executable_file.value, "Contents/MacOS/ImageJ-macosx") else: executable = os.path.join( default_output_directory, self.executable_directory.value.split("|")[1], self.executable_file.value) cmd = [ executable, "--headless", "console", "--run", os.path.join(default_output_directory, self.macro_directory.value.split("|")[1], self.macro_file.value) ] cmd += [self.stringify_metadata(tempdir)] subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) for image_group in self.image_groups_out: if not os.path.exists( os.path.join(tempdir, image_group.input_filename.value)): msg = f"CellProfiler couldn't find the output expected from the ImageJ Macro," \ f"\n File {image_group.input_filename.value} was missing" raise FileNotFoundError("Missing file", msg) image_pixels = skimage.io.imread( os.path.join(tempdir, image_group.input_filename.value)) workspace.image_set.add(image_group.image_name.value, Image(image_pixels, convert=False)) finally: # Clean up temp directory regardless of macro success for subdir, dirs, files in os.walk(tempdir): for file in files: os.remove(os.path.join(tempdir, file)) os.removedirs(tempdir) pixel_data = [] image_names = [] if self.show_window: for x in itertools.chain(self.image_groups_in, self.image_groups_out): pixel_data.append( workspace.image_set.get_image( x.image_name.value).pixel_data) image_names.append(x.image_name.value) workspace.display_data.pixel_data = pixel_data workspace.display_data.display_names = image_names workspace.display_data.dimensions = workspace.image_set.get_image( self.image_groups_out[0].image_name.value).dimensions
def run(self, workspace): default_output_directory = get_default_output_directory() tag = "runimagejmacro_" + str(random.randint(100000, 999999)) tempdir = os.path.join(default_output_directory, tag) os.makedirs(tempdir, exist_ok=True) try: for image_group in self.image_groups_in: image = workspace.image_set.get_image( image_group.image_name.value) image_pixels = image.pixel_data skimage.io.imsave( os.path.join(tempdir, image_group.output_filename.value), image_pixels) if self.executable_file.value[-4:] == ".app": executable = os.path.join( default_output_directory, self.executable_directory.value.split("|")[1], self.executable_file.value, "Contents/MacOS/ImageJ-macosx") else: executable = os.path.join( default_output_directory, self.executable_directory.value.split("|")[1], self.executable_file.value) cmd = [ executable, "--headless", "console", "--run", os.path.join(default_output_directory, self.macro_directory.value.split("|")[1], self.macro_file.value) ] cmd += [self.stringify_metadata(tempdir)] result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True) for image_group in self.image_groups_out: if not os.path.exists( os.path.join(tempdir, image_group.input_filename.value)): # Cleanup the error logs for display, we want to remove less-useful lines to keep it succinct. reject = ('console:', 'Java Hot', 'at org', 'at java', '[WARNING]', '\t') # ImageJ tends to report the same few lines over and over, so we'll use a dict as an ordered set. err = {} for line in result.stdout.splitlines(): if len(line.strip()) > 0 and not line.startswith( reject): err[line] = None if len(err) > 1: # Error appears when file loading fails, but can also show up if the macro failed to generate # an output image. We remove this if it wasn't the only error, as it can be confusing. err.pop('Unsupported format or not found', None) err = "\n".join(err.keys()) msg = f"CellProfiler couldn't find the output expected from the ImageJ Macro," \ f"\n File {image_group.input_filename.value} was missing." if err: msg += f"\n\nImageJ logs contained the following: \n{err}" raise FileNotFoundError("Missing file", msg) image_pixels = skimage.io.imread( os.path.join(tempdir, image_group.input_filename.value)) workspace.image_set.add(image_group.image_name.value, Image(image_pixels, convert=False)) finally: want_delete = True # Optionally clean up temp directory regardless of macro success if workspace.pipeline.test_mode and self.debug_mode: want_delete = False if not get_headless(): import wx message = f"Debugging was enabled.\nTemporary folder was not deleted automatically" \ f"\n\nTemporary subfolder is {os.path.split(tempdir)[-1]} in your Default Output Folder\n\nDo you want to delete it now?" with wx.Dialog(None, title="RunImageJMacro Debug Mode") as dlg: text_sizer = dlg.CreateTextSizer(message) sizer = wx.BoxSizer(wx.VERTICAL) dlg.SetSizer(sizer) button_sizer = dlg.CreateStdDialogButtonSizer( flags=wx.YES | wx.NO) open_temp_folder_button = wx.Button( dlg, -1, "Open temporary folder") button_sizer.Insert(0, open_temp_folder_button) def on_open_temp_folder(event): import sys if sys.platform == "win32": os.startfile(tempdir) else: import subprocess subprocess.call([ "open", tempdir, ]) open_temp_folder_button.Bind(wx.EVT_BUTTON, on_open_temp_folder) sizer.Add(text_sizer, 0, wx.EXPAND | wx.ALL, 10) sizer.Add(button_sizer, 0, wx.EXPAND | wx.ALL, 10) dlg.SetEscapeId(wx.ID_NO) dlg.SetAffirmativeId(wx.ID_YES) dlg.Fit() dlg.CenterOnParent() if dlg.ShowModal() == wx.ID_YES: want_delete = True if want_delete: try: for subdir, dirs, files in os.walk(tempdir): for file in files: os.remove(os.path.join(tempdir, file)) os.removedirs(tempdir) except: logging.error( "Unable to delete temporary directory, files may be in use by another program." ) logging.error( "Temp folder is subfolder {tempdir} in your Default Output Folder.\nYou may need to remove it manually." ) else: logging.error( f"Debugging was enabled.\nDid not remove temporary folder at {tempdir}" ) pixel_data = [] image_names = [] if self.show_window: for x in itertools.chain(self.image_groups_in, self.image_groups_out): pixel_data.append( workspace.image_set.get_image( x.image_name.value).pixel_data) image_names.append(x.image_name.value) workspace.display_data.pixel_data = pixel_data workspace.display_data.display_names = image_names workspace.display_data.dimensions = workspace.image_set.get_image( self.image_groups_out[0].image_name.value).dimensions