def __init__(self): super().__init__() # Initialize UI states self.currName = None self.currRow = None self.currRoiSize = gvars.roi_draw_radius self.donor_first = self.getConfig(gvars.key_firstFrameIsDonor) self.donor_is_left = self.getConfig(gvars.key_donorLeft) self.bg_correction = self.getConfig(gvars.key_illuCorrect) self.batchLoaded = ( False # If videos have been batchloaded, disable some controls ) # Initialize interface self.ui = Ui_MainWindow() self.ui.setupUi(self) # Spot counter labels self.labels = ( self.ui.labelColocGreenRedSpots, self.ui.labelGreenSpots, self.ui.labelRedSpots, ) self.setupListView(use_layoutbox=False) self.setupFigureCanvas(ax_type="img", use_layoutbox=False) self.setupPlot() self.setupSplitter(layout=self.ui.LayoutBox) # Spinbox triggers self.spinBoxes = (self.ui.spotsGrnSpinBox, self.ui.spotsRedSpinBox) self.ui.spotsGrnSpinBox.valueChanged.connect( partial(self.displaySpotsSingle, "green") ) self.ui.spotsRedSpinBox.valueChanged.connect( partial(self.displaySpotsSingle, "red") ) # Contrast boxes self.contrastBoxesLo = ( self.ui.contrastBoxLoGreen, self.ui.contrastBoxLoRed, ) self.contrastBoxesHi = ( self.ui.contrastBoxHiGreen, self.ui.contrastBoxHiRed, ) for contrastBox in self.contrastBoxesLo + self.contrastBoxesHi: contrastBox.valueChanged.connect(self.refreshPlot) self.ui.contrastBoxHiGreen.setValue( self.getConfig(gvars.key_contrastBoxHiGrnVal) ) self.ui.contrastBoxHiRed.setValue( self.getConfig(gvars.key_contrastBoxHiRedVal) ) self.show()
def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.inputs = Inputs() self.canvas = PlotCanvas() self.ui.mpl_LayoutBox.addWidget(self.canvas) self.connect_ui() self.traces = pd.DataFrame() self.values_from_gui() self.show()
class VideoWindow(BaseWindow): """ Main UI for the application. """ def __init__(self): super().__init__() # Initialize UI states self.currName = None self.currRow = None self.currRoiSize = gvars.roi_draw_radius self.donor_first = self.getConfig(gvars.key_firstFrameIsDonor) self.donor_is_left = self.getConfig(gvars.key_donorLeft) self.bg_correction = self.getConfig(gvars.key_illuCorrect) self.batchLoaded = ( False # If videos have been batchloaded, disable some controls ) # Initialize interface self.ui = Ui_MainWindow() self.ui.setupUi(self) # Spot counter labels self.labels = ( self.ui.labelColocGreenRedSpots, self.ui.labelGreenSpots, self.ui.labelRedSpots, ) self.setupListView(use_layoutbox=False) self.setupFigureCanvas(ax_type="img", use_layoutbox=False) self.setupPlot() self.setupSplitter(layout=self.ui.LayoutBox) # Spinbox triggers self.spinBoxes = (self.ui.spotsGrnSpinBox, self.ui.spotsRedSpinBox) self.ui.spotsGrnSpinBox.valueChanged.connect( partial(self.displaySpotsSingle, "green")) self.ui.spotsRedSpinBox.valueChanged.connect( partial(self.displaySpotsSingle, "red")) # Contrast boxes self.contrastBoxesLo = ( self.ui.contrastBoxLoGreen, self.ui.contrastBoxLoRed, ) self.contrastBoxesHi = ( self.ui.contrastBoxHiGreen, self.ui.contrastBoxHiRed, ) for contrastBox in self.contrastBoxesLo + self.contrastBoxesHi: contrastBox.valueChanged.connect(self.refreshPlot) self.ui.contrastBoxHiGreen.setValue( self.getConfig(gvars.key_contrastBoxHiGrnVal)) self.ui.contrastBoxHiRed.setValue( self.getConfig(gvars.key_contrastBoxHiRedVal)) self.show() def returnContainerInstance(self): """Returns appropriate data container for implemented windows""" return self.data.videos def enablePerWindow(self): """ Disables specific commands that should be unavailable for certain window types. Export commands should be accessible from all windows (no implicit behavior). """ self.ui: Ui_MenuBar menulist = ( self.ui.actionRemove_File, self.ui.actionRemove_All_Files, self.ui.actionColocalize_All, self.ui.actionFind_Show_Traces, self.ui.actionClear_Traces, self.ui.actionClear_and_Rerun, ) for menu in menulist: menu.setEnabled(True) self.ui.actionClose.setEnabled(False) def currentVideo(self) -> VideoContainer: """ Quick interface to obtain file data (or names will be extremely long). Add type hinting in metadata to improve autocomplete. """ return self.data.get(self.currName) def newTraceFromVideo(self, n) -> TraceContainer: """ Shortcut to obtain trace, and create a new one if it doesn't exist. """ tracename = self.currName + "_" + str(n) if tracename not in self.data.traces: self.data.traces[tracename] = TraceContainer(filename=tracename, video=self.currName, n=n) return self.data.traces[tracename] def trace_c(self, n, channel) -> TraceChannel: """ Shortcut to obtain trace channel. See newTraceFromVideo(). """ if channel == "green": return self.newTraceFromVideo(n).grn elif channel == "red": return self.newTraceFromVideo(n).red elif channel == "acc": return self.newTraceFromVideo(n).acc else: raise ValueError("Invalid channel") def openFile(self): """ Open file to load in. """ if not self.getConfig(gvars.key_batchLoadingMode): directory = self.getLastOpenedDir() filenames, selectedFilter = QFileDialog.getOpenFileNames( self, caption="Open File", filter="Video files (*.tif *fits)", directory=directory, ) if len(filenames) > 0: progressbar = ProgressBar(loop_len=len(filenames), parent=self) for i, full_filename in enumerate(filenames): if progressbar.wasCanceled(): break # Make sure name is unique uniqueName = lib.utils.generate_unique_name( full_filename=full_filename, array=self.data.videos.keys(), ) self.data.load_video_data( path=full_filename, name=uniqueName, donor_is_first=self.donor_first, donor_is_left=self.donor_is_left, bg_correction=self.bg_correction, ) item = QStandardItem(uniqueName) item.setCheckable(False) self.currName = uniqueName self.currDir = os.path.dirname(full_filename) self.listModel.appendRow(item) # refresh listView self.listView.repaint() progressbar.increment() # Select first video if loading into an empty listView if self.currRow is None: self.currRow = 0 self.selectListViewTopRow() index = self.listModel.index(self.currRow, 0) name = self.listModel.data(index) self.currName = name # Write most recently opened directory to getConfig file, # but only if a file was selected if self.currDir is not None: self.setConfig(gvars.key_lastOpenedDir, self.currDir) else: self.batchOpen() def batchOpen(self): """Loads one video at a time and extracts traces, then clears the video from memory afterwards""" directory = self.getLastOpenedDir() trace_window = self.windows[gvars.TraceWindow] # type: TraceWindow filenames, selectedFilter = QFileDialog.getOpenFileNames( self, caption="Open File", filter="Video files (*.tif *.fits)", directory=directory, ) if len(filenames) > 0: self.processEvents() progressbar = ProgressBar(loop_len=len(filenames), parent=self) for i, full_filename in enumerate(filenames): if progressbar.wasCanceled(): break else: progressbar.increment() self.currName = os.path.basename(full_filename) if self.currName in self.data.videos: continue self.data.load_video_data( path=full_filename, name=os.path.basename(full_filename), donor_is_first=self.donor_first, donor_is_left=self.donor_is_left, bg_correction=self.bg_correction, ) channels = ("green", "red") for c in channels: if self.currentVideo().acc.exists: self.colocalizeSpotsSingleVideo(channel=c, find_npairs="auto") else: self.colocalizeSpotsSingleVideo(channel=c, find_npairs="spinbox") self.getTracesSingleVideo() self.currentVideo().vid = None for c in self.currentVideo().channels + ( self.currentVideo().acc, ): c.raw = None self.listModel.appendRow(QStandardItem(self.currName)) self.listView.repaint() self.currDir = os.path.dirname(full_filename) if self.currDir is not None: self.setConfig(gvars.key_lastOpenedDir, self.currDir) if len(self.data.traces) > 0: currently_loaded = trace_window.returnCurrentListViewNames() # Iterate over all filenames and add to list for name in self.data.traces.keys(): # If name is already in list, skip it if name in currently_loaded: continue item = QStandardItem(name) item.setCheckable(True) trace_window.listModel.appendRow(item) trace_window.selectListViewTopRow() trace_window.getCurrentListObject() trace_window.show() self.batchLoaded = True self.refreshInterface() self.selectListViewTopRow() self.refreshPlot() @timeit def colocalizeSpotsSingleVideo(self, channel, find_npairs="spinbox"): """ Find and colocalize spots for a single currentVideo (not displayed). """ vid = self.currentVideo() tolerance_type = self.getConfig(gvars.key_colocTolerance) tolerance_value = gvars.roi_coloc_tolerances[tolerance_type] if channel == "green": channel = vid.grn spinBox = self.ui.spotsGrnSpinBox pairs = ((vid.grn, vid.red), ) colocs = (vid.coloc_grn_red, ) elif channel == "red": channel = vid.red spinBox = self.ui.spotsRedSpinBox pairs = ((vid.grn, vid.red), ) colocs = (vid.coloc_grn_red, ) else: raise ValueError("Invalid color") if find_npairs == "spinbox": find_npairs = spinBox.value() elif find_npairs == "auto": find_npairs = self.getConfig(gvars.key_autoDetectPairs) else: raise ValueError("Select from 'spinbox' or 'auto'") if self.getConfig(gvars.key_fitSpots): if find_npairs > 0: # hardcoded value threshold until I come up with something # better spots = lib.imgdata.find_spots(channel.mean_nobg, value=20, method="laplacian_of_gaussian") # Sort spots based on intensity real_spots = [] for spot in spots: masks = lib.imgdata.circle_mask(yx=spot, indices=vid.indices, **gvars.cmask_p) intensity, bg = lib.imgdata.tiff_stack_intensity( channel.mean_nobg, *masks, raw=True) if intensity > bg * 1.05: real_spots.append(spot) channel.n_spots = len(real_spots) channel.spots = real_spots else: if find_npairs > 0: channel.spots = lib.imgdata.find_spots( channel.mean_nobg, value=find_npairs, method="peak_local_max", ) channel.n_spots = len(channel.spots) if channel == "red" and self.getConfig(gvars.key_unColocRed): vid.grn.spots = vid.red.spots vid.acc.spots = vid.red.spots vid.grn.n_spots = vid.red.n_spots vid.acc.n_spots = vid.red.n_spots for (c1, c2), coloc in zip(pairs, colocs): if all((c1.n_spots, c2.n_spots)) > 0: coloc.spots = lib.imgdata.colocalize_rois( c1.spots, c2.spots, color1=coloc.color1, color2=coloc.color2, tolerance=tolerance_value, ) coloc.n_spots = len(coloc.spots) vid.coloc_all.spots = vid.coloc_grn_red.spots vid.coloc_all.n_spots = vid.coloc_grn_red.n_spots def displaySpotsSingle(self, channel): """ Displays colocalized spot for a single video. """ self.getCurrentListObject() if self.currName is not None: self.colocalizeSpotsSingleVideo(channel) self.refreshPlot() def colocalizeSpotsAllVideos(self): """ Colocalizes spots for all videos, with the same threshold. Use this method instead for progress bar. """ progressbar = ProgressBar(loop_len=len(self.data.videos.keys()), parent=self) for name in self.data.videos.keys(): self.currName = name for c in "green", "red": self.colocalizeSpotsSingleVideo(c) progressbar.increment() self.resetCurrentName() self.refreshPlot() def getTracesSingleVideo(self): """ Gets traces from colocalized ROIs, for a single video. """ if self.currName is None: return vid = self.currentVideo() # Clear all traces previously held traces whenever this is called vid.traces = {} if vid.coloc_grn_red.spots is None: for c in "green", "red": self.colocalizeSpotsSingleVideo(c) else: for n, *row in vid.coloc_grn_red.spots.itertuples(): yx_grn, yx_red = lib.utils.pairwise(row) trace = self.newTraceFromVideo(n) # Green if vid.grn.exists and yx_grn is not None: masks_grn = lib.imgdata.circle_mask(yx=yx_grn, indices=vid.indices, **gvars.cmask_p) ( trace.grn.int, trace.grn.bg, ) = lib.imgdata.tiff_stack_intensity(vid.grn.raw, *masks_grn, raw=True) # Red masks_red = lib.imgdata.circle_mask(yx=yx_red, indices=vid.indices, **gvars.cmask_p) trace.red.int, trace.red.bg = lib.imgdata.tiff_stack_intensity( vid.red.raw, *masks_red, raw=True) # Acceptor (if FRET) if vid.acc.exists: ( trace.acc.int, trace.acc.bg, ) = lib.imgdata.tiff_stack_intensity(vid.acc.raw, *masks_red, raw=True) trace.fret = lib.math.calc_E(trace.get_intensities()) trace.stoi = lib.math.calc_S(trace.get_intensities()) trace.frames = np.arange(1, len(trace.red.int) + 1) trace.frames_max = max(trace.frames) def getTracesAllVideos(self): """ Gets the traces from all videos that have colocalized ROIs. """ for name in self.data.videos.keys(): self.currName = name for c in "green", "red": self.colocalizeSpotsSingleVideo(c) self.getTracesSingleVideo() self.resetCurrentName() def savePlot(self): """ Saves plot with colors suitable for export (e.g. white background). """ self.setSavefigrcParams() if self.currName is not None: self.canvas.defaultImageName = self.currName self.canvas.defaultImageName = self.currName else: self.canvas.defaultImageName = "Blank" for ax in self.canvas.axes_all: ax.tick_params(axis="both", colors=gvars.color_hud_black) for spine in ax.spines.values(): spine.set_edgecolor(gvars.color_hud_black) self.canvas.toolbar.save_figure() # Reset figure colors after plotting for ax in self.canvas.axes_all: ax.tick_params(axis="both", colors=gvars.color_hud_white) for spine in ax.spines.values(): spine.set_edgecolor(gvars.color_hud_white) self.refreshPlot() def setupPlot(self): """ Set up plot for MainWindow. """ self.canvas.fig.set_facecolor(gvars.color_hud_black) self.canvas.fig.set_edgecolor(gvars.color_hud_white) for ax in self.canvas.axes_all: for spine in ax.spines.values(): spine.set_edgecolor(gvars.color_hud_white) def refreshPlot(self): """ Refreshes plot with selected list item. """ for ax in self.canvas.axes_all: ax.tick_params(axis="both", colors=gvars.color_hud_white) ax.clear() if self.currName is not None: vid = self.currentVideo() roi_radius = vid.roi_radius contrast_lo = ( self.ui.contrastBoxLoGreen, self.ui.contrastBoxLoRed, ) keys = ( gvars.key_contrastBoxHiGrnVal, gvars.key_contrastBoxHiRedVal, ) contrast_hi = ( self.ui.contrastBoxHiGreen, self.ui.contrastBoxHiRed, ) # Rescale values according to UI first # might break image if too high sensitivity = 250 for c, lo, hi in zip( vid.channels, contrast_lo, contrast_hi ): # type: ImageChannel, QDoubleSpinBox, QDoubleSpinBox clip_lo = float(lo.value() / sensitivity) clip_hi = float(hi.value() / sensitivity) c.rgba = lib.imgdata.rescale_intensity(c.mean, range=(clip_lo, clip_hi)) # Save contrast settings for hi, cfg in zip(contrast_hi, keys): self.setConfig(cfg, hi.value()) # Single channels for img, ax in zip(vid.channels, self.canvas.axes_single): if img.rgba is not None: # Avoid imshow showing blank if clipped too much if np.isnan(img.rgba).any(): img.rgba.fill(1) ax.imshow(img.rgba, cmap=img.cmap, vmin=0) else: lib.plotting.empty_imshow(ax) c1, c2 = vid.grn, vid.red if c1.rgba is not None and c2.rgba is not None: self.canvas.ax_grn_red.imshow( lib.imgdata.light_blend(c1.rgba, c2.rgba, cmap1=c1.cmap, cmap2=c2.cmap), vmin=0, ) else: lib.plotting.empty_imshow(self.canvas.axes_blend.ax) for ax in self.canvas.axes_all: ax.set_xticks(()) ax.set_yticks(()) # Green spots if vid.grn.n_spots > 0: lib.plotting.plot_rois( vid.grn.spots, self.canvas.ax_grn, color=gvars.color_white, radius=roi_radius, ) # Red spots if vid.red.n_spots > 0: lib.plotting.plot_rois( vid.red.spots, self.canvas.ax_red, color=gvars.color_white, radius=roi_radius, ) # Colocalized spots if vid.coloc_grn_red.spots is not None: lib.plotting.plot_roi_coloc( vid.coloc_grn_red.spots, img_ax=self.canvas.ax_grn_red, color1=gvars.color_green, color2=gvars.color_red, radius=roi_radius, ) else: for ax in self.canvas.axes_all: lib.plotting.empty_imshow(ax) self.canvas.draw() self.refreshInterface() def refreshInterface(self): """ Repaints UI labels to match the current plot shown. """ if self.currName is not None: vid = self.currentVideo() channels = ( vid.coloc_grn_red, vid.grn, vid.red, ) for channel, label in zip(channels, self.labels): label.setText(str(channel.n_spots)) self.ui.spotsGrnSpinBox.setDisabled(not vid.grn.exists) self.ui.spotsRedSpinBox.setDisabled(not vid.red.exists) if self.batchLoaded: self.disableSpinBoxes(( "green", "red", )) else: for label in self.labels: label.setText(str("-")) # Repaint all labels for label in self.labels: label.repaint() def findTracesAndShow(self): """ Gets the name of currently stored traces and puts them into the trace listView. """ trace_window = self.windows[gvars.TraceWindow] if len(self.data.traces) == 0: # Load all traces into their respective videos, and generate a # list of traces self.getTracesAllVideos() currently_loaded = self.returnCurrentListViewNames() # Iterate over all filenames and add to list for (name, trace) in self.data.traces.items(): if name in currently_loaded: continue item = QStandardItem(trace.name) trace_window.listModel.appendRow(item) trace_window.currName = trace.name item.setCheckable(True) trace_window.selectListViewTopRow() else: trace_window.show() trace_window.refreshPlot() trace_window.show() def clearTraceAndRerun(self): """ Clears everything and reruns on selected videos. Loads all traces into their respective videos, and generates a list of traces """ trace_window = self.windows[gvars.TraceWindow] self.clearTraces() self.getTracesAllVideos() # Iterate over all filenames and add to list for (name, trace) in self.data.traces.items(): item = QStandardItem(trace.name) trace_window.listModel.appendRow(item) trace_window.currName = trace.name item.setCheckable(True) if trace_window.isVisible(): trace_window.selectListViewTopRow() trace_window.refreshPlot() def newTraceFromContainer(self, trace, n): """ Creates an empty video object to load traces into by transplanting a list of loaded TraceContainers """ tracename = self.currName + "_" + str(n) trace.currentVideo = self.currName trace.name = tracename trace.n = n if tracename not in self.data.videos[self.currName].traces: self.data.videos[self.currName].traces[tracename] = trace def disableSpinBoxes(self, channel): """ Disables all spinboxes. Order must be as below, or a Qt bug will re-enable the boxes. """ if "red" in channel: self.ui.spotsRedSpinBox.setDisabled(True) self.ui.spotsRedSpinBox.repaint() if "green" in channel: self.ui.spotsGrnSpinBox.setDisabled(True) self.ui.spotsGrnSpinBox.repaint() def _debug(self): """Debug for MainWindow.""" pass
class MainWindow(QMainWindow): """ The main window that does everything """ def __init__(self): super().__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) self.inputs = Inputs() self.canvas = PlotCanvas() self.ui.mpl_LayoutBox.addWidget(self.canvas) self.connect_ui() self.traces = pd.DataFrame() self.values_from_gui() self.show() def connect_ui(self): """Connectnumber interface""" # Connect all checkboxes dynamically [ getattr(self.ui, c).clicked.connect(self.refresh_ui) for c in dir(self.ui) if c.startswith("checkBox") ] self.ui.pushButtonRefresh.clicked.connect(self.refresh_plots) self.ui.pushButtonExport.clicked.connect(self.export_traces_to_ascii) def refresh_ui(self): """Refreshes UI to e.g. disable some input boxes""" for inputBox, checkBox in ( (self.ui.inputDonorMeanLifetime, self.ui.checkBoxDlifetime), (self.ui.inputAcceptorMeanLifetime, self.ui.checkBoxALifetime), ( self.ui.inputTransitionProbabilityHi, self.ui.checkBoxTransitionProbability, ), (self.ui.inputFretStateMeans, self.ui.checkBoxRandomState), (self.ui.inputNoiseHi, self.ui.checkBoxNoise), (self.ui.inputMismatchHi, self.ui.checkBoxMismatch), (self.ui.inputScalerHi, self.ui.checkBoxScaler), (self.ui.inputBleedthroughHi, self.ui.checkBoxBleedthrough), ): inputBox.setDisabled(checkBox.isChecked()) self.ui.inputMaxRandomStates.setEnabled( self.ui.checkBoxRandomState.isChecked()) def values_from_gui(self): """ Fetch values from GUI """ # Number of examples self.inputs.n_examples = int( self.ui.examplesComboBox.currentText().split("x")[0]) self.inputs.n_examples **= 2 # Number of traces to export self.inputs.n_traces = int(self.ui.inputNumberOfTraces.value()) # Trace length self.inputs.trace_len = int(self.ui.inputTraceLength.value()) # Scramble probability self.inputs.scramble_prob = float( self.ui.inputScrambleProbability.value()) # Aggregation probability self.inputs.aggregate_prob = float( self.ui.inputAggregateProbability.value()) # Max aggregate size self.inputs.max_aggregate_size = int( self.ui.inputMaxAggregateSize.value()) # FRET state means if self.ui.checkBoxRandomState.isChecked(): self.inputs.fret_means = "random" else: self.inputs.fret_means = lib.utils.numstring_to_ls( self.ui.inputFretStateMeans.text()) # Max number of random states self.inputs.max_random_states = int( self.ui.inputMaxRandomStates.value()) # Donor mean lifetime if self.ui.checkBoxDlifetime.isChecked(): self.inputs.donor_lifetime = None else: self.inputs.donor_lifetime = int( self.ui.inputDonorMeanLifetime.value()) # Acceptor mean lifetime if self.ui.checkBoxALifetime.isChecked(): self.inputs.acceptor_lifetime = None else: self.inputs.acceptor_lifetime = int( self.ui.inputAcceptorMeanLifetime.value()) # Blinking probability self.inputs.blinking_prob = float( self.ui.inputBlinkingProbability.value()) # Transition Probability if self.ui.checkBoxTransitionProbability.isChecked(): self.inputs.transition_prob = float( self.ui.inputTransitionProbabilityLo.value()) else: self.inputs.transition_prob = ( float(self.ui.inputTransitionProbabilityLo.value()), float(self.ui.inputTransitionProbabilityHi.value()), ) # Noise if self.ui.checkBoxNoise.isChecked(): self.inputs.noise = float(self.ui.inputNoiseLo.value()) else: self.inputs.noise = ( float(self.ui.inputNoiseLo.value()), float(self.ui.inputNoiseHi.value()), ) # Acceptor-only mismatch if self.ui.checkBoxMismatch.isChecked(): self.inputs.aa_mismatch = float(self.ui.inputMismatchLo.value()) else: self.inputs.aa_mismatch = ( float(self.ui.inputMismatchLo.value()), float(self.ui.inputMismatchHi.value()), ) # Donor Bleedthrough if self.ui.checkBoxBleedthrough.isChecked(): self.inputs.bleed_through = float( self.ui.inputBleedthroughLo.value()) else: self.inputs.bleed_through = ( float(self.ui.inputBleedthroughLo.value()), float(self.ui.inputBleedthroughHi.value()), ) # Scaler if self.ui.checkBoxScaler.isChecked(): self.inputs.scaling_factor = float(self.ui.inputScalerLo.value()) else: self.inputs.scaling_factor = ( float(self.ui.inputScalerLo.value()), float(self.ui.inputScalerHi.value()), ) def set_traces(self, n_traces): """Generate traces to show in the GUI or export""" if n_traces > 50: update_freq = 5 progressbar = ProgressBar(parent=self, loop_len=n_traces / update_freq) else: update_freq = None progressbar = None self.traces = lib.algorithms.generate_traces( n_traces=n_traces, aa_mismatch=self.inputs.aa_mismatch, state_means=self.inputs.fret_means, random_k_states_max=self.inputs.max_random_states, max_aggregate_size=self.inputs.max_aggregate_size, aggregation_prob=self.inputs.aggregate_prob, scramble_prob=self.inputs.scramble_prob, trace_length=self.inputs.trace_len, trans_prob=self.inputs.transition_prob, blink_prob=self.inputs.blinking_prob, bleed_through=self.inputs.bleed_through, noise=self.inputs.noise, D_lifetime=self.inputs.donor_lifetime, A_lifetime=self.inputs.acceptor_lifetime, au_scaling_factor=self.inputs.scaling_factor, discard_unbleached=False, null_fret_value=-1, min_state_diff=0.2, acceptable_noise=0.25, progressbar_callback=progressbar, callback_every=update_freq, ) if progressbar is not None: progressbar.close() def refresh_plots(self): """Refreshes preview plots""" self.values_from_gui() # generate at least enough traces to show required number of examples if self.inputs.n_traces < self.inputs.n_examples: self.inputs.n_traces = self.inputs.n_examples self.set_traces(self.inputs.n_examples) self.canvas.flush_events() self.canvas.fig.clear() n_subplots = self.inputs.n_examples nrows = int(self.inputs.n_examples**(1 / 2)) ncols = nrows outer_grid = GridSpec(nrows, ncols, wspace=0.1, hspace=0.1) # 2x2 grid for i in range(n_subplots): trace = self.traces[self.traces["name"] == i] inner_subplot = GridSpecFromSubplotSpec( nrows=5, ncols=1, subplot_spec=outer_grid[i], wspace=0, hspace=0, height_ratios=[3, 3, 3, 3, 1], ) axes = [ plt.Subplot(self.canvas.fig, inner_subplot[n]) for n in range(5) ] ax_g_r, ax_red, ax_frt, ax_sto, ax_lbl = axes bleach = trace["_bleaches_at"].values[0] tmax = trace["frame"].max() fret_states = np.unique(trace["E_true"]) fret_states = fret_states[fret_states != -1] ax_g_r.plot(trace["DD"], color="seagreen") ax_g_r.plot(trace["DA"], color="salmon") ax_red.plot(trace["AA"], color="red") ax_frt.plot(trace["E"], color="orange") ax_frt.plot(trace["E_true"], color="black", ls="-", alpha=0.3) for state in fret_states: ax_frt.plot([0, bleach], [state, state], color="red", alpha=0.2) ax_sto.plot(trace["S"], color="purple") lib.utils.plot_category(y=trace["label"], ax=ax_lbl, alpha=0.4) for ax in ax_frt, ax_sto: ax.set_ylim(-0.15, 1.15) for ax, s in zip((ax_g_r, ax_red), (trace["DD"], trace["AA"])): ax.set_ylim(s.max() * -0.15) ax.plot([0] * len(s), color="black", ls="--", alpha=0.5) for ax in axes: for spine in ax.spines.values(): spine.set_edgecolor("darkgrey") if bleach is not None: ax.axvspan(bleach, tmax, color="black", alpha=0.1) ax.set_xticks(()) ax.set_yticks(()) ax.set_xlim(0, tmax) self.canvas.fig.add_subplot(ax) self.canvas.draw() def export_traces_to_ascii(self): """ Opens a folder dialog to save traces to ASCII .txt files """ self.set_traces(n_traces=int(self.ui.inputNumberOfTraces.value())) df = self.traces diag = ExportDialog(init_dir="~/Desktop/", accept_label="Export") if diag.exec(): outdir = diag.selectedFiles()[0] appctxt.app.processEvents() else: outdir = None df.index = np.arange(0, len(df), 1) // int( self.ui.inputTraceLength.value()) if outdir is not None: for idx, trace in df.groupby(df.index): bg = np.zeros(len(trace)) path = os.path.join( outdir, "trace_{}_{}.txt".format(idx, time.strftime("%Y%m%d_%H%M")), ) df = pd.DataFrame({ "D-Dexc-bg": bg, "A-Dexc-bg": bg, "A-Aexc-bg": bg, "D-Dexc-rw": trace["DD"], "A-Dexc-rw": trace["DA"], "A-Aexc-rw": trace["AA"], "S": trace["S"], "E": trace["E"], }).round(4) date_txt = "Date: {}".format(time.strftime("%Y-%m-%d, %H:%M")) mov_txt = "Movie filename: {}".format(None) id_txt = "FRET pair #{}".format(idx) bl_txt = "Bleaches at {}".format(trace["fb"].values[0]) with open(path, "w") as f: exp_txt = "Simulated trace exported by Fiddler" f.write("{0}\n" "{1}\n" "{2}\n" "{3}\n" "{4}\n\n" "{5}".format( exp_txt, date_txt, mov_txt, id_txt, bl_txt, df.to_csv(index=False, sep="\t"), ))