def openfiles(self, paths): """ Override openfiles method in base plugin. Used to open a tomography dataset from the recognized file formats and instantiate a viewer.TomoViewer tab. This function takes quite a bit, consider running this in a background thread Parameters ---------- paths : str/list Path to file. Currently only one file is supported. Multiple paths (ie stack of tiffs should be easy to implement using the formats.StackImage class. """ msg.showMessage('Loading file...', timeout=10) self.activate() if type(paths) is list: paths = paths[0] # # create file name to pass to manager (?) # file_name = paths.split("/")[-1] # self.working_dir = paths.split(file_name)[0] widget = TomoViewer(paths=paths) widget.sigSetDefaults.connect(self.manager.setPipelineFromDict) widget.wireupCenterSelection(self.manager.recon_function) self.centerwidget.addTab(widget, os.path.basename(paths)) self.centerwidget.setCurrentWidget(widget)
def RMC_done(self): """ Slot to receive signal when HipRMC calculation is done. Emits signal to main thread to load output """ run_time = time.time() - self.start_time if not self.interrupt: os.rename(self.hig_name, '{}/{}.hig'.format(self.rmc_folder, self.save_name)) # write output of RMC to file in hiprmc output folder output_path = self.rmc_folder + "/{}_rmc_output.txt".format(self.save_name) with open(output_path, 'w') as txt: txt.write(self.output) msg.showMessage('HipRMC complete. Run time: {:.2f} s'.format(run_time)) self.emitter.sigFinished.emit() else: try: os.rename(self.hig_name, '{}/{}.hig'.format(self.rmc_folder, self.save_name)) except OSError: pass msg.showMessage('HipRMC interrupted by user. Run time: {:.2f} s'.format(run_time)) self.interrupt = False
def opendirectory(self, files, operation=None): """ Override opendirectory method in base plugin. Used to open a tomography dataset from the recognized file formats and instantiate a viewer.TomoViewer tab. Currently not completely implemented Parameters ---------- paths : str/list Path to dir """ msg.showMessage('Loading directory...', timeout=10) self.activate() try: if type(files) is list: files = files[0] widget = TomoViewer(paths=files) except Exception as e: msg.showMessage('Unable to load directory. Check log for details.', timeout=10) raise e widget.sigSetDefaults.connect(self.manager.setPipelineFromDict) widget.wireupCenterSelection(self.manager.recon_function) self.centerwidget.addTab(widget, os.path.basename(files)) self.centerwidget.setCurrentWidget(widget)
def slicePreviewAction(self, message='Computing slice preview...', fixed_func=None, prange=None): """ Called when a reconstruction preview is requested either by the toolbar button or by the test parameter range from a parameter. Parameters ---------- message : str, optional Message to log. Test Parameters log a different message than the default fixed_func : type class A dynamic class with only the necessary attributes to be run in a workflow pipeline. This is used for parameter range tests to create the class with the parameter to be run and send it to a background thread. See FunctionManager.testParameterRange for more details prange : dict, optional Dictionary containing parameter being tested for TestParamRange, and the function the parameter belongs to """ if self.checkPipeline(): msg.showMessage(message, timeout=0) prev_slice = self.centerwidget.currentWidget( ).sinogramViewer.currentIndex dims = self.get_reader_dims(sino=(prev_slice, prev_slice + 1, 1)) dims += (0, ) self.preview_slices = self.centerwidget.widget( self.currentIndex()).sinogramViewer.currentIndex self.processFunctionStack( callback=lambda *x: self.runSlicePreview(*x), dims=dims, fixed_func=fixed_func, prange=prange)
def loadFullReconstruction(self): """ Sets up a full reconstruction for the current dataset based on the current workflow pipeline and configuration parameters. Does not run reconstruction if there is one already running. Called when the corresponding toolbar button is clicked. """ if not self.checkPipeline(): return value = QtGui.QMessageBox.question(None, 'Run Full Reconstruction', 'You are about to run a full reconstruction. ' 'This step can take some minutes. Do you want to continue?', (QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel)) if value is QtGui.QMessageBox.Cancel: return currentWidget = self.centerwidget.widget(self.currentWidget()) self.manager.updateParameters() run_state = self.manager.saveState(currentWidget) recon_iter = threads.iterator(callback_slot=self.bottomwidget.log2local, interrupt_signal=self.bottomwidget.local_cancelButton.clicked, finished_slot=self.reconstructionFinished)(self.manager.reconGenerator) # pstart = self.ui.config_params.child('Start Projection').value() # pend = self.ui.config_params.child('End Projection').value() # pstep = self.ui.config_params.child('Step Projection').value() # sstart = self.ui.config_params.child('Start Sinogram').value() # send = self.ui.config_params.child('End Sinogram').value() # sstep = self.ui.config_params.child('Step Sinogram').value() proj = None sino = None chunk = None for f in self.manager.features: if 'Reader' in f.name: proj = f.projections sino = f.sinograms chunk = f.chunk if (not proj and not sino and not chunk) or (not proj[1] and not sino[1] and not chunk): sino = (0, currentWidget.data.shape[2], 1) proj = (0, currentWidget.data.shape[0], 1) chunk = cpu_count()*5 args = (currentWidget, run_state, proj, sino, chunk, cpu_count()) self.manager.recon_queue.put([recon_iter, args]) if self.recon_running: name = self.centerwidget.tabText(self.centerwidget.currentIndex()) msg.showMessage('Queued reconstruction for {}.'.format(name), timeout=0) self.runReconstruction()
def reconstructionFinished(self): """ Slot to revieve the reconstruction background threads finished signal. Runs another reconstruction is there is one on the queue """ msg.showMessage('Reconstruction complete.', timeout=10) self.recon_running = False self.runReconstruction()
def freeRecon(self): """ Frees plugin to run reconstruction and run next in queue when job is canceled """ msg.showMessage("Reconstruction interrupted.", timeout=0) self.bottom.log2local( '---------- RECONSTRUCTION INTERRUPTED ----------') self.queue_widget.removeRecon(0) self.recon_running = False self.runReconstruction()
def opendirectory(self, files, operation=None): msg.showMessage('Loading directory...', timeout=10) self.activate() if type(files) is list: files = files[0] widget = TomoViewer(paths=files) widget.sigSetDefaults.connect(self.manager.setPipelineFromDict) widget.wireupCenterSelection(self.manager.recon_function) self.centerwidget.addTab(widget, os.path.basename(files)) self.centerwidget.setCurrentWidget(widget)
def preview3DAction(self): """ Called when a reconstruction 3D preview is requested either by the toolbar button. The process is almost equivalent to running a slice preview except a different slice object is passed to extract a subsampled array from the raw tomographic array """ if self.checkPipeline(): msg.showMessage('Computing 3D preview...', timeout=0) slc = (slice(None), slice(None, None, 8), slice(None, None, 8)) self.manager.cor_scale = lambda x: x // 8 self.processFunctionStack(callback=lambda x: self.run3DPreview(*x), slc=slc)
def multiSlicePreviewAction(self, message='Computing multi-slice preview...'): """ Called when a multiple slice reconstructin preview is requested by the toolbar buttong Parameters ---------- message : str, optional Message to log. Test Parameters log a different message than the default """ slice_no = self.centerwidget.widget( self.currentIndex()).sinogramViewer.currentIndex maximum = self.centerwidget.widget( self.currentIndex()).sinogramViewer.data.shape[0] - 1 dialog = sliceDialog(parent=self.centerwidget, val1=slice_no, val2=slice_no + 20, maximum=maximum) try: value = dialog.value if value is None: pass elif type(value) == str: msg.showMessage(value, timeout=0) else: if self.checkPipeline(): msg.showMessage(message, timeout=0) if value[0] == value[1]: dims = self.get_reader_dims(sino=(value[1], value[1] + 1, 1)) dims += (0, ) self.preview_slices = value[1] self.centerwidget.widget( self.currentIndex()).sinogramViewer.setIndex( self.preview_slices) self.processFunctionStack( callback=lambda *x: self.runSlicePreview(*x), dims=dims, fixed_func=None) else: dims = self.get_reader_dims(sino=(value[0], value[1] + 1, 1)) dims += (0, ) self.preview_slices = [value[0], value[1]] self.processFunctionStack( callback=lambda *x: self.runSlicePreview(*x), dims=dims, fixed_func=None) except AttributeError: pass
def currentChanged(self, current, previous): item = self.itemFromIndex(current) try: if item.childCount() == 0: msg.showMessage('Loading preview...') dataset = item.parent().parent().text(0) stage = item.parent().text(0) bg_get_preview = threads.method( callback_slot=self.sigItemPreview.emit, except_slot=self.handleException)(self.client.get_image_as) bg_get_preview(dataset, stage, index=0) except AttributeError: pass
def runReconstruction(self): """ Takes reconstruction job from self.manager.recon_queue and runs it on background thread. Saves function pipeline as python runnable after reconstruction is finished. """ if (not self.manager.recon_queue.empty()) and (not self.recon_running): self.recon_running = True recon_job = self.manager.recon_queue.get() args = recon_job[1] name = self.centerwidget.tabText(self.centerwidget.indexOf(args[0])) msg.showMessage('Computing reconstruction for {}...'.format(name), timeout=0) recon_job[0](*args)
def reconstructionFinished(self): """ Slot to revieve the reconstruction background threads finished signal. Runs another reconstruction is there is one on the queue """ msg.showMessage('Reconstruction complete.', timeout=10) self.queue_widget.removeRecon(0) if len(self.queue_widget.recon_queue) > 0: self.bottom.log2local( '------- Beginning next reconstruction -------') self.recon_running = False self.runReconstruction()
def loadFullReconstruction(self): """ Sets up a full reconstruction for the current dataset based on the current workflow pipeline and configuration parameters. Does not run reconstruction if there is one already running. Called when the corresponding toolbar button is clicked. """ if not self.checkPipeline(): return value = QtGui.QMessageBox.question( None, 'Run Full Reconstruction', 'You are about to run a full reconstruction. ' 'This step can take some minutes. Do you want to continue?', (QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel)) if value is QtGui.QMessageBox.Cancel: return currentWidget = self.centerwidget.currentWidget() self.manager.updateParameters() func_dict, theta, center, pipeline_dict, run_dict = self.manager.saveState( currentWidget) recon_iter = threads.iterator( callback_slot=self.bottom.log2local, except_slot=self.reconstructionFinished, interrupt_signal=self.bottom.local_cancelButton.clicked, finished_slot=self.reconstructionFinished)( self.manager.reconGenerator) # set up information for reconstruction proj, sino, width, proj_chunk, sino_chunk = self.get_reader_dims() dims = (proj, sino, width, sino_chunk, proj_chunk, cpu_count()) args = (currentWidget, func_dict, theta, center, pipeline_dict, run_dict, dims) self.queue_widget.recon_queue.append([recon_iter, args]) self.queue_widget.addRecon(args) if self.recon_running: name = self.centerwidget.tabText(self.centerwidget.currentIndex()) msg.showMessage('Queued reconstruction for {}.'.format(name), timeout=0) self.runReconstruction()
def openfiles(self, paths): """ Override openfiles method in base plugin. Used to open a tomography dataset from the recognized file formats and instantiate a viewer.TomoViewer tab. This function takes quite a bit, consider running this in a background thread Parameters ---------- paths : str/list Path to file. Currently only one file is supported. Multiple paths (ie stack of tiffs should be easy to implement using the formats.StackImage class. """ msg.showMessage('Loading file...', timeout=10) self.activate() try: if type(paths) is list: paths = paths[0] widget = TomoViewer(toolbar=self.toolbar, paths=paths) except Exception as e: msg.showMessage('Unable to load file. Check log for details.', timeout=10) raise e # connect signals widget.sigSetDefaults.connect(self.manager.setPipelineFromDict) widget.projectionViewer.sigROIWidgetChanged.connect( lambda x: x.sigRegionChanged.connect(self.manager. adjustReaderParams)) # complicated way of connecting the ROI params to the functionwidget # is there a better way to do this? self.manager.sigNormFuncAdded.connect(lambda x: x.sigROIAdded.connect( widget.projectionViewer.stackViewer.view.addItem)) self.manager.sigNormFuncAdded.connect(lambda x: x.sigROIAdded.connect( lambda y: y.sigRegionChanged.connect(lambda z: x.adjustParams( self.manager)))) self.wireCORWidgets(widget) self.centerwidget.addTab(widget, os.path.basename(paths)) self.centerwidget.setCurrentWidget(widget)
def runDask(self): import client.dask_active_executor if client.dask_active_executor.active_executor is None: #warning message return ae = client.dask_active_executor.active_executor.executor def hipgisaxs_func(yaml_str): import subprocess import time timestamp = time.strftime("%Y.%m.%d.%H.%M.%S") filename = os.path.join(os.path.expanduser('~'), "test_remote.yml") with open(filename, 'w') as outfile: outfile.write(yaml_str) a = subprocess.check_output([ "srun", "--job-name=hipgisaxs", "--nodes=1", "--ntasks=1", "--ntasks-per-node=1", "--time=00:30:00", "/bin/bash", "/users/course79/rungisaxs.sh", filename ]) return a self.writeyaml() with open(os.path.join(os.path.expanduser('~'), 'test.yml'), 'r') as outfile: fx_str = outfile.read() msg.showMessage('Submitting job to remote executor...') future_tag = ae.submit(hipgisaxs_func, fx_str, pure=False) msg.showMessage('Job received. Submitting to queue...') import time while future_tag.status == "pending": #msg.showMessage("Waiting for response from server...",timeout=5) time.sleep(1) if future_tag.status == "failure": msg.showMessage("Execution failed.", timeout=5) return msg.showMessage("Execution complete. Fetching result...", timeout=5) result = future_tag.result() out = np.array( [np.fromstring(line, sep=' ') for line in result.splitlines()]) msg.logMessage(("result = ", out), msg.DEBUG) plugins.plugins['Viewer'].instance.opendata(out)
def serve(self): msg.logMessage("Serving: " + self.command, msg.INFO) channel = self.client.get_transport().open_session() msg.logMessage(channel.get_pty(), msg.DEBUG) # channel.exec_command('tty') channel.exec_command(self.command) readytorun = False while True: if channel.exit_status_ready(): break rl, wl, xl = select.select([channel], [], [], 10.0) if len(rl) > 0: line = channel.recv(1024) msg.logMessage(line) if 'queued and waiting for resources' in line: msg.showMessage( 'Execution queued and waiting for resources...') elif 'has been allocated resources' in line: msg.showMessage( 'Execution has been allocated resources...') readytorun = True if readytorun and line: msg.showMessage('Executing job...') readytorun = False if line.find("Password") >= 0: msg.logMessage("writing password", msg.DEBUG) channel.sendall(self.password + "\n") msg.logMessage("Ending Dask Scheduler", msg.INFO)
def multiSlicePreviewAction(self, message='Computing multi-slice preview...', fixed_func=None): slice_no = self.centerwidget.widget(self.currentWidget()).sinogramViewer.currentIndex maximum = self.centerwidget.widget(self.currentWidget()).sinogramViewer.data.shape[0]-1 dialog = sliceDialog(parent=None, val1=slice_no, val2=slice_no+20,maximum=maximum) try: value = dialog.value if value is None: pass elif type(value) == str: msg.showMessage(value,timeout=0) else: if self.checkPipeline(): msg.showMessage(message, timeout=0) if value[0] == value[1]: self.preview_slices = value[1] self.processFunctionStack(callback=lambda x: self.runSlicePreview(*x),fixed_func=fixed_func) else: self.preview_slices = [value[0],value[1]] slc = (slice(None,None,None), slice(value[0],value[1]+1,1), slice(None,None,None)) self.processFunctionStack(callback=lambda x: self.runSlicePreview(*x), slc=slc, fixed_func=fixed_func) except AttributeError: pass
def preview3DAction(self): """ Called when a reconstruction 3D preview is requested either by the toolbar button. The process is almost equivalent to running a slice preview except a different slice object is passed to extract a subsampled array from the raw tomographic array. User chooses subsample factor from pop-up window. """ if self.checkPipeline(): window = QtGui.QInputDialog(self.centerwidget) window.setIntValue(8) window.setWindowTitle('3D Preview subsample factor') window.setLabelText( 'Choose a subsample factor for the 3D preview: ') window.exec_() val = window.intValue() if window.result(): msg.showMessage('Computing 3D preview...', timeout=0) dims = self.get_reader_dims(sino=(None, None, val), width=(None, None, val)) dims += (0, ) self.processFunctionStack( callback=lambda *x: self.run3DPreview(*x), dims=dims)
def runFullReconstruction(self): """ Sets up a full reconstruction to be run in a background thread for the current dataset based on the current workflow pipeline and configuration parameters. Called when the corresponding toolbar button is clicked. Made obsolete by loadFullReconstruction and runReconstruction """ if not self.checkPipeline(): return value = QtGui.QMessageBox.question(None, 'Run Full Reconstruction', 'You are about to run a full reconstruction. ' 'This step can take some minutes. Do you want to continue?', (QtGui.QMessageBox.Yes | QtGui.QMessageBox.Cancel)) if value is QtGui.QMessageBox.Cancel: return name = self.centerwidget.tabText(self.centerwidget.currentIndex()) msg.showMessage('Computing reconstruction for {}...'.format(name),timeout = 0) self.bottomwidget.local_console.clear() self.manager.updateParameters() recon_iter = threads.iterator(callback_slot=self.bottomwidget.log2local, interrupt_signal=self.bottomwidget.local_cancelButton.clicked, finished_slot=self.reconstructionFinished)(self.manager.functionStackGenerator)
def runSlicePreview(self, datawidget, func_dict, theta, center, stack_dict, prange=None, dims=None): """ Callback function that receives the necessary widgets/information required to run a preview and add it to the viewer.TomoViewer.previewViewer Parameters ---------- datawidget : viewers.TomoViewer Widget containing dataset func_dict: dict Dictionary of function names and partials with keywords for the reconstruction theta: list List of values representing angular location of camera (for reconstruction) center: float Center of rotation of dataset stack_dict : dict Dictionary describing the workflow pipeline being run. This is displayed to the left of the preview image in the viewer.TomoViewer.previewViewer prange: dict, optional Dictionary containing parameter being tested for TestParamRange, and the function the parameter belongs to dims : tuple, optional Tuple containing dimensions of dataset to be reconstructed """ callback = partial(self.centerwidget.currentWidget().addSlicePreview, stack_dict, slice_no=self.preview_slices, prange=prange) err_message = 'Unable to compute slice preview. Check log for details.' except_slot = lambda: msg.showMessage(err_message) bg_fold = threads.iterator(callback_slot=callback, finished_slot=msg.clearMessage, lock=threads.mutex, except_slot=except_slot) bg_fold(self.manager.reconGenerator)(datawidget, func_dict, theta, center, None, None, dims, None, 'Slice')
def run3DPreview(self, datawidget, func_dict, theta, center, stack_dict, prange=None, dims=None): """ Callback function that receives the partial stack and corresponding dictionary required to run a preview and add it to the viewer.TomoViewer.preview3DViewer Parameters ---------- datawidget : viewers.TomoViewer Widget containing dataset func_dict: dict Dictionary of function names and partials with keywords for the reconstruction theta: list List of values representing angular location of camera (for reconstruction) center: float Center of rotation of dataset stack_dict : dict Dictionary describing the workflow pipeline being run. This is displayed to the left of the preview image in the viewer.TomoViewer.previewViewer dims : tuple, optional Tuple containing dimensions of dataset to be reconstructed """ self.manager.updateParameters() callback = partial( self.centerwidget.widget(self.currentIndex()).add3DPreview, stack_dict) err_message = 'Unable to compute 3D preview. Check log for details.' except_slot = lambda: msg.showMessage(err_message) bg_fold = threads.iterator(callback_slot=callback, finished_slot=msg.clearMessage, lock=threads.mutex, except_slot=except_slot) bg_fold(self.manager.reconGenerator)(datawidget, func_dict, theta, center, None, None, dims, None, '3D')
def foldPreviewStack(self, partial_stack, initializer, data_dict, callback, error_message): """ Calls the managers foldFunctionStack on a background thread. This is what tells the manager to compute a slice preview or a 3D preview from a specified workflow pipeline Parameters ---------- partial_stack : list of functools.partial List of partials that require only the input array to run. initializer : ndarray Array to use as initializer for folding operation callback : function function to be called with the return value of the fold (ie the resulting reconstruction). This is the current TomoViewers addSlicePreview or add3DPreview methods error_message : str Message to log/display if the fold process raises an exception """ except_slot = lambda: msg.showMessage(error_message) bg_fold = threads.method(callback_slot=callback, finished_slot=msg.clearMessage, lock=threads.mutex, except_slot=except_slot) # bg_fold(self.manager.foldFunctionStack)(partial_stack, initializer) bg_fold(self.manager.foldSliceStack)(partial_stack, data_dict)
def __init__(self, paths, worker, parent=None): """ Class that holds image to be processed by HipRMC, image after it has been centered, and HipRMC output Attributes ---------- emitter : threads.Emitter Holds and emits a signal when fHipRMc done processing interrupt : bool flag - set true if rmc processing was interrupted; affects post-rmc processes cameraLocation : tuple 2-tuple (x,y) of camera location on input image rmcView : ximcam.RmcView.rncView Timeline viewer which holds and displays HipRMC output orig_image: np.array Original input image edited_image : np.array Image with camera location adjusted to its center orig_view : pyqtgraph.ImageView Holds the original image edited_view : pyqtgraph.ImageView Holds the image after camera location adjustment image_holder : QtGui.StackedWidget Main widget of plugin. Holds original and edited images, as well as HipRMC output, in tabs scatteringParams : pyqtgraph.parametertree Occupies right side of main widget. Holds configparams configparams : pyqtgraph.Parameter Class held by scatteringParams which holds parameter values for HipRMC output, err : str Output and error from HipRMC subprocess call headings : QtGui.QTabBar Displays name of corresponding tab of image_holder Parameters ---------- paths : str/list of str Path to input dataset worker: threads.Worker Worker which queues up jobs and runs them on a QtCore.QThreadpool parent : QtGui.QWidget parent widget args Additional arguments kwargs Additional keyword arguments """ super(inOutViewer, self).__init__(parent=parent) self.emitter = threads.Emitter() self.interrupt = False self.cameraLocation = config.activeExperiment.center self.rmc_view= None self.edited_image = None self.worker = worker # holders for original and edited images self.orig_view = LogViewer() self.orig_view.setContentsMargins(0,0,0,0) self.edited_view = LogViewer() self.edited_view.setContentsMargins(0,0,0,0) if type(paths) == list: self.path = paths[0] else: self.path = paths self.image_holder = QtGui.QStackedWidget() self.image_holder.setContentsMargins(0,0,0,0) # configuring right widget sideWidget = QtGui.QWidget() sideWidgetFormat = QtGui.QVBoxLayout() sideWidgetFormat.setContentsMargins(0, 0, 0, 0) # if paths is None, inOutViewer will only hold HipRMC output and the images/parameter table are not necessary if paths is not None: self.orig_image = np.transpose(loader.loadimage(self.path)) if len(self.orig_image.shape) > 2: self.orig_image = np.transpose(self.orig_image).swapaxes(0,1) while len(self.orig_image.shape) > 2: self.orig_image = self.orig_image[:,:,0] self.orig_view.setImage(self.orig_image) self.orig_view.autoRange() try: start_size = max(self.orig_image.shape)/10 except ValueError: msg.showMessage("Image must be 2-D") scatteringHolder = QtGui.QStackedWidget() image_name = self.path.split('/')[-1].split('.')[0] self.scatteringParams = pt.ParameterTree() params = [{'name': 'Num tiles', 'type': 'int', 'value': 1, 'default': 1}, {'name': 'Loading factor', 'type': 'float', 'value': 0.5, 'default': 0.5}, {'name': 'Scale factor', 'type': 'int', 'value': 32, 'default': 32}, {'name': 'Numsteps factor', 'type': 'int', 'value': 100, 'default': 100}, {'name': 'Model start size', 'type': 'int', 'value': start_size}, {'name': 'Save name', 'type': 'str', 'value': 'hiprmc_' + image_name}, {'name': 'Mask image', 'type': 'str'}] self.configparams = pt.Parameter.create(name='Configuration', type='group', children=params) self.scatteringParams.setParameters(self.configparams, showTop=False) scatteringHolder.addWidget(self.scatteringParams) # # is there a better way to check for correct dimensions? # if len(self.orig_image.shape) > 2: # shape = (self.orig_image.shape[1], self.orig_image.shape[2]) # else: # shape = self.orig_image.shape self.drawROI(0, 0, self.orig_image.shape[0], self.orig_image.shape[1], 'r', self.orig_view.getImageItem().getViewBox()) scatteringHolder.setFixedHeight(300) sideWidgetFormat.addWidget(scatteringHolder) centerButton = QtGui.QPushButton("Center camera location") runButton = QtGui.QPushButton("Run RMC processing") stopButton = QtGui.QPushButton("Stop RMC") sideWidgetFormat.addSpacing(5) sideWidgetFormat.addWidget(centerButton) sideWidgetFormat.addSpacing(5) sideWidgetFormat.addWidget(runButton) sideWidgetFormat.addSpacing(5) sideWidgetFormat.addWidget(stopButton) sideWidgetFormat.addStretch(10) sideWidget.setLayout(sideWidgetFormat) # connect buttons to processing centerButton.clicked.connect(self.center) runButton.clicked.connect(self.runRMC) stopButton.clicked.connect(self.stop_threads) # tab headings for main widget self.headings = QtGui.QTabBar(self) self.headings.addTab('Original Image') self.headings.addTab('Recentered Image') self.headings.addTab('RMC Timeline') self.headings.addTab('FFT RMC Timeline') self.headings.setShape(QtGui.QTabBar.TriangularSouth) leftWidget = QtGui.QWidget() sidelayout = QtGui.QVBoxLayout() sidelayout.addWidget(self.image_holder) sidelayout.addWidget(self.headings) leftWidget.setLayout(sidelayout) fullPlugin = QtGui.QSplitter() fullPlugin.addWidget(leftWidget) fullPlugin.addWidget(sideWidget) h = QtGui.QHBoxLayout() h.setContentsMargins(0, 0, 0, 0) h.addWidget(fullPlugin) self.setLayout(h) self.image_holder.addWidget(self.orig_view) self.image_holder.addWidget(self.edited_view) self.headings.currentChanged.connect(self.currentChanged) self.image_holder.currentChanged.connect(self.headings.setCurrentIndex)
def getDatasets(self, query): msg.showMessage('Searching SPOT database...') search = threads.method(callback_slot=self.createDatasetDictionary, finished_slot=msg.clearMessage)( self.client.search) search(query, **self.search_params)
def handleException(self, ex, tb): msg.showMessage('Unable to fetch preview from SPOT.') msg.logMessage(ex, level=40)
def hiprmc_not_found(self): """ Slot to receive exception signal in case hiprmc is not found. """ msg.showMessage('Cannot find HipRMC executable. Cannot run HipRMC.') QtGui.QMessageBox.critical(self, 'Error', 'Cannot find HipRMC executable. Cannot run HipRMC.')
def runRMC(self): """ Slot to receive signal when user requests HipRMC calculation. Writes hig file of parameter values and calls HipRMC as subprocess """ msg.showMessage('Running RMC for centered version of {}'.format(self.path), timeout=0) if self.rmc_view is not None: self.image_holder.removeWidget(self.rmc_view) if self.edited_image is None: msg.showMessage('Error: must center image before running HipRMC',timeout = 0) msg.clearMessage() return params = self.configparams hig_info = {'hipRMCInput': {'instrumentation': {'inputimage': "{}".format(self.write_path_sample), 'imagesize': [self.new_dim, self.new_dim ], 'numtiles': params.child('Num tiles').value(), 'loadingfactors': [params.child('Loading factor').value()]}, 'computation': {'runname': "{}".format(params.child('Save name').value()), 'modelstartsize': [params.child('Model start size').value(), params.child('Model start size').value()], 'numstepsfactor': params.child('Numsteps factor').value(), 'scalefactor': params.child('Scale factor').value()}}} self.mask_path = params.child('Mask image').value() if self.mask_path and self.mask_path != "None": self.mask = np.transpose(loader.loadimage(self.mask_path)) self.center(False) hig_info['hipRMCInput']['instrumentation']['maskimage'] = "{}".format(self.write_path_mask) h = hig.hig(**hig_info) self.hig_name = os.path.join(os.path.abspath('.'), params.child('Save name').value()) if not self.hig_name.endswith('.hig'): self.hig_name += '.hig' # write hig file to disk h.write(self.hig_name) self.save_name = params.child('Save name').value() self.start_time = time.time() # starts filewatcher to watch for new hiprmc folder, and the HipRMC job # also starts worker if it is not already running process = threads.RunnableMethod(method = self.run_RMCthread, finished_slot = self.RMC_done, except_slot=self.hiprmc_not_found) self.file_watcher = NewFolderWatcher(path=os.path.abspath("."), experiment=None) # when filewatcher gets rmc folder, it passes it to self.start_watcher to start another watcher self.file_watcher.sigFinished.connect(self.start_watcher) watcher = threads.RunnableMethod(method=self.file_watcher.run,) self.worker.queue.put(watcher) self.worker.queue.put(process) if not self.worker.isRunning(): self.worker.start()
def __init__(self, app): QtCore.QObject.__init__(self, app) print 'Gui:\t\t\t', QtGui.QApplication.instance().thread() QtGui.QFontDatabase.addApplicationFont("xicam/gui/zerothre.ttf") import plugins config.activate() self._pool = None # Load the gui from file self.app = app guiloader = QUiLoader() f = QtCore.QFile("xicam/gui/mainwindow.ui") f.open(QtCore.QFile.ReadOnly) self.ui = guiloader.load(f) f.close() # STYLE with open('xicam/gui/style.stylesheet', 'r') as f: style = f.read() app.setStyleSheet(qdarkstyle.load_stylesheet() + style) app.setAttribute(QtCore.Qt.AA_DontShowIconsInMenus, False) # INITIAL GLOBALS self.viewerprevioustab = -1 self.timelineprevioustab = -1 self.experiment = config.experiment() self.folderwatcher = watcher.newfilewatcher() self.plugins = [] # ACTIONS # Wire up action buttons self.ui.findChild(QtGui.QAction, 'actionOpen').triggered.connect(self.dialogopen) self.ui.findChild(QtGui.QAction, 'actionSettings').triggered.connect( self.settingsopen) self.ui.findChild(QtGui.QAction, 'actionQuit').triggered.connect( QtGui.QApplication.instance().quit) self.ui.actionExport_Image.triggered.connect(self.exportimage) # Grab status bar msg.statusbar = self.ui.statusbar pb = QtGui.QProgressBar() pb.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Ignored) msg.progressbar = pb pb.setAccessibleName('progressbar') msg.statusbar.addPermanentWidget(pb) pb.hide() msg.showMessage('Ready...') xglobals.statusbar = self.ui.statusbar # TODO: Deprecate this by replacing all statusbar calls with msg module # PLUG-INS placeholders = [ self.ui.viewmode, self.ui.sidemode, self.ui.bottommode, self.ui.toolbarmode, self.ui.leftmode ] plugins.initplugins(placeholders) plugins.plugins['MOTD'].instance.activate() plugins.base.fileexplorer.sigOpen.connect(self.openfiles) plugins.base.fileexplorer.sigFolderOpen.connect(self.openfolder) plugins.base.booltoolbar.actionTimeline.triggered.connect( plugins.base.filetree.handleOpenAction) pluginmode = plugins.widgets.pluginModeWidget(plugins.plugins) self.ui.modemenu.addWidget(pluginmode) self.ui.menubar.addMenu(plugins.buildactivatemenu(pluginmode)) # TESTING ## # self.openimages(['../samples/AgB_00016.edf']) # self.openimages(['/Users/rp/Data/LaB6_Ant1_dc002p.mar3450']) # self.calibrate() # self.updatepreprocessing() ## testmenu = QtGui.QMenu('Testing') testmenu.addAction('Single frame').triggered.connect(self.singletest) testmenu.addAction('Image stack').triggered.connect(self.stacktest) testmenu.addAction('Timeline').triggered.connect(self.timelinetest) testmenu.addAction('Tilt').triggered.connect(self.tilttest) self.ui.menubar.addMenu(testmenu) # DASK WORKFLOW # TODO turn this into a class # convert the following into a class self.sessions = ["localhost", "Andromeda", "Daint", "NERSC/Edison"] self.session_machines = [ "localhost", "andromeda.dhcp.lbl.gov", "148.187.1.7", "edison.nersc.gov" ] # self.session_address = ["localhost", socket.gethostbyname("andromeda.dhcp.lbl.gov"), "148.187.26.16", ""] self.session_address = [ "localhost", "andromeda.dhcp.lbl.gov", "148.187.26.16", "" ] self.session_exec = [ "", "/home/hari/runscript.sh", "/users/course79/runscript.sh", "/usr/common/graphics/visit/camera/runscript.sh" ] self.executors = [None, None, None, None] self.sessionmenu = QtGui.QMenu('Sessions') # comboBoxAction = ComboBoxAction("Active Session", self.sessionmenu); self.actionGroup = QtGui.QActionGroup(self.sessionmenu) for i in self.sessions: action = QtGui.QAction(i, self.sessionmenu, checkable=True) if i == "localhost": action.setChecked(True) action.triggered.connect(self.activesessionchanged) self.actionGroup.addAction(action) self.sessionmenu.addAction(action) # self.comboBoxAction.comboBox().activated.connect(self.activesessionchanged) # self.sessionmenu.addAction(comboBoxAction) self.ui.menubar.addMenu(self.sessionmenu) # self.daskLoop = client.dask_io_loop.DaskLoop() # try: # # create a local active executor # local_scheduler = client.dask_local_scheduler.LocalScheduler(self.daskLoop) # local_scheduler.execute() # self.executors[0] = local_scheduler # self.sessionmenu.setTitle("Active Session (localhost)") # client.dask_active_executor.active_executor = local_scheduler # except: # msg.logMessage("Issues connecting to localhost",msg.ERROR) # START PYSIDE MAIN LOOP # Show UI and end app when it closes self.ui.installEventFilter(self)
def center(self, sample=True): """ Slot to receive signal when user requests a centered image. Performs centering and writes new image into current working directory Parameters ---------- sample: boolean, optional flag whether image to be centered is the original sample or the mask image """ if sample: if self.edited_image is not None: msg.showMessage('Image already centered.') return image = self.orig_image else: image = self.mask #resize image so that it's in center and displays output if a sample image xdim = int(image.shape[0]) ydim = int(image.shape[1]) newx = xdim + 2*abs(self.cameraLocation[0]-xdim/2) newy = ydim + 2*abs(self.cameraLocation[1]-ydim/2) self.new_dim = max(newx,newy) self.edited_image = np.ones((self.new_dim,self.new_dim),dtype = np.int) new_center = (self.new_dim/2,self.new_dim/2) lowleft_corner_x = int(new_center[0]-self.cameraLocation[0]) lowleft_corner_y = int(new_center[1]-self.cameraLocation[1]) self.edited_image[lowleft_corner_x:lowleft_corner_x+xdim,lowleft_corner_y: lowleft_corner_y+ydim] = image # save image if sample: self.write_path = self.path if self.write_path.endswith('.tif'): self.write_path = self.write_path[:-4] + '_centered.tif' else: self.write_path += '_centered.tif' self.write_path_sample = self.write_path img = tifimage.tifimage(np.rot90((self.edited_image.astype(float) / self.edited_image.max() * 2 ** 16).astype(np.int16))) else: self.write_path = self.mask_path if self.write_path.endswith('.tif'): self.write_path = self.write_path[:-4] + '_centered.tif' else: self.write_path += '_centered.tif' self.write_path_mask = self.write_path img = tifimage.tifimage(np.rot90(self.edited_image.astype(float))) img.write(self.write_path) if sample: self.edited_view.setImage(self.edited_image) box = self.drawCameraLocation(self.edited_view,new_center) self.drawROI(lowleft_corner_x,lowleft_corner_y,xdim,ydim,'r', box) self.drawROI(0,0,self.new_dim,self.new_dim, 'b', box) # this is a temporary fix for a problem: pushing a button changes tab back to first self.image_holder.setCurrentIndex(1)