diff --git a/shapeout2/gui/quick_view/qv_main.py b/shapeout2/gui/quick_view/qv_main.py index 482b172..d9aa910 100644 --- a/shapeout2/gui/quick_view/qv_main.py +++ b/shapeout2/gui/quick_view/qv_main.py @@ -133,6 +133,19 @@ def __init__(self, *args, **kwargs): levels=(0, 255), ) + self.img_info = { + "image": {"view_event": self.imageView_image, + "view_poly": self.imageView_image_poly, + "cmap": pg.colormap.get('CET-L1')}, + "qpi_pha": {"view_event": self.imageView_image_pha, + "view_poly": self.imageView_image_poly_pha, + "cmap": pg.colormap.get('CET-D1A')}, + "qpi_amp": { + "view_event": self.imageView_image_amp, + "view_poly": self.imageView_image_poly_amp, + "cmap": pg.colormap.get('CET-L1')}, + } + # set initial empty dataset self._rtdc_ds = None self.slot = None @@ -201,7 +214,7 @@ def __setstate__(self, state): self.checkBox_image_contour.setChecked(event["image contour"]) self.checkBox_image_zoom.setChecked(event["image zoom"]) self.checkBox_image_background.setChecked( - event["image background"]) + event["image background"]) self.spinBox_event.setValue(event["index"]) self.checkBox_trace_raw.setChecked(event["trace raw"]) self.checkBox_trace_legend.setChecked(event["trace legend"]) @@ -250,28 +263,47 @@ def rtdc_ds(self, rtdc_ds): contains_bg_feat = "image_bg" in rtdc_ds self.checkBox_image_background.setVisible(contains_bg_feat) - def get_event_image(self, ds, event): + def get_event_image(self, ds, event, feat): state = self.__getstate__() imkw = self.imkw.copy() - cellimg = ds["image"][event] - # apply background correction - if "image_bg" in ds: - if state["event"]["image background"]: - bgimg = ds["image_bg"][event].astype(np.int16) - cellimg = cellimg.astype(np.int16) - cellimg = cellimg - bgimg + int(np.mean(bgimg)) - # automatic contrast - if state["event"]["image auto contrast"]: - vmin, vmax = cellimg.min(), cellimg.max() - cellimg = (cellimg - vmin) / (vmax - vmin) * 255 - # convert to RGB - cellimg = cellimg.reshape( - cellimg.shape[0], cellimg.shape[1], 1) - cellimg = np.repeat(cellimg, 3, axis=2) - # clip and convert to int - cellimg = np.clip(cellimg, 0, 255) - cellimg = np.require(cellimg, np.uint8, 'C') + cellimg = ds[feat][event] + + if feat == "image": + # apply background correction + if "image_bg" in ds: + if state["event"]["image background"]: + bgimg = ds["image_bg"][event].astype(np.int16) + cellimg = cellimg.astype(np.int16) + cellimg = cellimg - bgimg + int(np.mean(bgimg)) + # automatic contrast + if state["event"]["image auto contrast"]: + vmin, vmax = cellimg.min(), cellimg.max() + cellimg = (cellimg - vmin) / (vmax - vmin) * 255 + elif "qpi" in feat: + if "qpi_pha" in feat: + imkw["levels"] = (-3, 3) + elif "qpi_amp" in feat: + imkw["levels"] = (0, 2) + else: + raise ValueError(f"Options for `feat` are 'image', " + f"'qpi_pha' and 'qpi_amp', got {feat}") + + if feat == "image": + # convert to RGB + cellimg = cellimg.reshape( + cellimg.shape[0], cellimg.shape[1], 1) + cellimg = np.repeat(cellimg, 3, axis=2) + + # clip and convert to int + cellimg = np.clip(cellimg, 0, 255) + cellimg = np.require(cellimg, np.uint8, 'C') + cellimg = self.display_contour(ds, event, state, cellimg, feat, imkw) + + return cellimg, imkw + + @staticmethod + def display_contour(ds, event, state, cellimg, feat, imkw): # Only load contour data if there is an image column. # We don't know how big the images should be so we # might run into trouble displaying random contours. @@ -283,9 +315,18 @@ def get_event_image(self, ds, event): # https://github.com/DC-analysis/dclab/issues/76 cont = mask ^ binary_erosion(mask) # set red contour pixel values in original image - cellimg[cont, 0] = int(255*.7) - cellimg[cont, 1] = 0 - cellimg[cont, 2] = 0 + red_pix = ((imkw["levels"][1] - imkw["levels"][0]) + * 0.7) - np.abs(imkw["levels"][0]) + if feat == "image": + cellimg[cont, 0] = int( + red_pix) if imkw["levels"][1] == 255 else red_pix + cellimg[cont, 1] = int(imkw["levels"][0]) + cellimg[cont, 2] = int(imkw["levels"][0]) + else: + # just 2D images (not RGB) + cellimg[cont] = int( + red_pix) if imkw["levels"][1] == 255 else red_pix + if state["event"]["image zoom"]: xv, yv = np.where(mask) idminx = xv.min() - 5 @@ -298,7 +339,7 @@ def get_event_image(self, ds, event): idmaxx = idmaxx if idmaxx < shx else shx idmaxy = idmaxy if idmaxy < shy else shy cellimg = cellimg[idminx:idmaxx, idminy:idmaxy] - return cellimg, imkw + return cellimg def get_statistics(self): if self.rtdc_ds is not None: @@ -334,25 +375,43 @@ def on_event_scatter_clicked(self, plot, point): ds_idx = np.where(plotted)[0][point.index()] self.show_event(ds_idx) + def display_img(self, feat, view, cellimg, **imkw): + self.img_info[feat][view].setImage(cellimg, **imkw) + self.img_info[feat][view].setColorMap(self.img_info[feat]["cmap"]) + self.img_info[feat][view].show() + def on_event_scatter_hover(self, pos): """Update the image view in the polygon widget """ if self.rtdc_ds is not None and self.toolButton_poly.isChecked(): + ds = self.rtdc_ds # plotted events plotted = self.widget_scatter.events_plotted spos = self.widget_scatter.scatter.mapFromView(pos) point = self.widget_scatter.scatter.pointAt(spos) # get corrected index event = np.where(plotted)[0][point.index()] - if "image" in self.rtdc_ds: - try: - cellimg, imkw = self.get_event_image(self.rtdc_ds, event) - except IndexError: - # the plot got updated, and we still have the old data - cellimg, imkw = self.get_event_image(self.rtdc_ds, 0) + + view = "view_poly" + for key in self.img_info.keys(): + self.img_info[key][view].hide() + + try: + # if we have qpi data, image might be a different shape + if "qpi_pha" in ds: + cellimg, imkw = self.get_event_image(ds, event, "qpi_pha") + self.display_img("qpi_pha", view, cellimg, **imkw) + if "qpi_amp" in ds: + cellimg, imkw = self.get_event_image(ds, event, "qpi_amp") + self.display_img("qpi_amp", view, cellimg, **imkw) + elif "image" in ds: + cellimg, imkw = self.get_event_image(ds, event, "image") + self.display_img("image", view, cellimg, **imkw) + + except IndexError: + # the plot got updated, and we still have the old data + cellimg, imkw = self.get_event_image(self.rtdc_ds, 0, "image") self.imageView_image_poly.setImage(cellimg, **imkw) - self.imageView_image_poly.show() - else: - self.imageView_image_poly.hide() + self.display_img("image", view, cellimg, **imkw) def on_event_scatter_spin(self, event): """Sping control for event selection changed""" @@ -494,8 +553,8 @@ def on_tool(self, collapse=False): else: # keep everything as-is but update the sizes show_event = self.stackedWidget.currentWidget() is self.page_event - show_settings = self.stackedWidget.currentWidget() \ - is self.page_settings + show_settings = ( + self.stackedWidget.currentWidget() is self.page_settings) show_poly = self.stackedWidget.currentWidget() is self.page_poly # toolbutton checked @@ -606,12 +665,25 @@ def show_event(self, event): if self.tabWidget_event.currentIndex() == 0: # update image state = self.__getstate__() - if "image" in ds: - cellimg, imkw = self.get_event_image(ds, event) - self.imageView_image.setImage(cellimg, **imkw) - self.groupBox_image.show() - else: - self.groupBox_image.hide() + self.groupBox_image.hide() + + view = "view_event" + for key in self.img_info.keys(): + self.img_info[key][view].hide() + + # if we have qpi data, image might be a different shape + if "qpi_pha" in ds: + cellimg, imkw = self.get_event_image(ds, event, "qpi_pha") + self.display_img("qpi_pha", view, cellimg, **imkw) + if "qpi_amp" in ds: + cellimg, imkw = self.get_event_image(ds, event, "qpi_amp") + self.display_img("qpi_amp", view, cellimg, **imkw) + elif "image" in ds: + cellimg, imkw = self.get_event_image(ds, event, "image") + self.display_img("image", view, cellimg, **imkw) + + self.groupBox_image.show() + if "trace" in ds: # remove legend items for item in reversed(self.legend_trace.items): @@ -650,8 +722,9 @@ def show_event(self, event): range_t[1] = flpos + 1.5 * flwidth range_t[2] = flmax # set legend name - ln = "{} {}".format(self.slot.fl_name_dict[ - "FL-{}".format(key[2])], key[4:]) + ln = "{} {}".format( + self.slot.fl_name_dict[ + "FL-{}".format(key[2])], key[4:]) self.legend_trace.addItem(self.trace_plots[key], ln) self.legend_trace.update() else: diff --git a/shapeout2/gui/quick_view/qv_main.ui b/shapeout2/gui/quick_view/qv_main.ui index 7607660..f901103 100644 --- a/shapeout2/gui/quick_view/qv_main.ui +++ b/shapeout2/gui/quick_view/qv_main.ui @@ -714,17 +714,53 @@ - - - - 300 - 100 - + + + QLayout::SetNoConstraint - - background-color:transparent + + 0 - + + + + + 300 + 100 + + + + background-color:transparent + + + + + + + + 300 + 100 + + + + background-color:transparent + + + + + + + + 300 + 100 + + + + background-color:transparent + + + + @@ -1039,17 +1075,71 @@ - - - - 0 - 0 - + + + QLayout::SetNoConstraint - - opacity: 0 + + 0 - + + + + + 0 + 0 + + + + + 300 + 100 + + + + opacity: 0 + + + + + + + + 0 + 0 + + + + + 300 + 100 + + + + opacity: 0 + + + + + + + + 0 + 0 + + + + + 300 + 100 + + + + opacity: 0 + + + +