diff --git a/grum/imgdesc.py b/grum/imgdesc.py new file mode 100644 index 0000000..5b171d5 --- /dev/null +++ b/grum/imgdesc.py @@ -0,0 +1,48 @@ +import numpy as np + + +class ImageDescription: + + def __init__(self, name, title=None, xlabel=None, ylabel=None, image=None): + self.name = name + self.title = title + self.xlabel = xlabel + self.ylabel = ylabel + self.image = image + + @property + def data(self): + return np.asarray(self.image) + + @data.setter + def data(self, value): + self.image = value + + + def append(self, xy): + print("ignored image append") + + def extend(self, data): + print("ignored image extend") + + + def make_plot(self, plotwidget, style): + res = plotwidget.setImage(self.data) + + if self.title: + plotwidget.setTitle(self.title) + + if self.xlabel: + plotwidget.setLabel("bottom", self.xlabel) + + if self.ylabel: + plotwidget.setLabel("left", self.ylabel) + + return res + + + def to_dict(self): + return {k: v for k, v in self.__dict__.items() if not k.startswith("_") and k != "name" and v is not None} + + + diff --git a/grum/mainwin.py b/grum/mainwin.py index a2e4fd9..a80e250 100644 --- a/grum/mainwin.py +++ b/grum/mainwin.py @@ -6,9 +6,10 @@ from .dictlist import DictList from .exampledata import exampledata from .h5filedlg import open_h5_files_dialog, save_h5_file_dialog from .io import write_dict, read_dict -from .mdi import MDIArea, MDISubMultiPlot, MDISubPlot, MDIWindowMode +from .mdi import MDIArea, MDISubMultiPlot, MDISubPlot, MDISubImage, MDIWindowMode from .menus import BarMenu from .plotdesc import PlotDescription +from .imgdesc import ImageDescription from .rpc import RPCServerThread from .shortcut import shortcut from .webview import WebView @@ -16,7 +17,8 @@ from .webview import WebView class MainWindow(QMainWindow): - sig_make_new_plot = pyqtSignal(str, PlotDescription) + sig_make_new_plot = pyqtSignal(str, PlotDescription) + sig_make_new_image = pyqtSignal(str, ImageDescription) def __init__(self, *args, title="grum", host="localhost", port=8000, offline=False, add_examples=False, window_mode=MDIWindowMode.MULTI, **kwargs): super().__init__(*args, **kwargs) @@ -88,8 +90,10 @@ class MainWindow(QMainWindow): rst.server.register_function(self.append_data) rst.server.register_function(self.extend_data) rst.server.register_function(self.set_data) + rst.server.register_function(self.new_image) self.sig_make_new_plot.connect(self.on_make_new_plot) + self.sig_make_new_image.connect(self.on_make_new_image) def keyPressEvent(self, event): @@ -140,12 +144,29 @@ class MainWindow(QMainWindow): desc.data = data self.sync_item_and_plots(item) + def new_image(self, name, cfg): + """ + Create a new image using the configuration dict . + The configuration is forwarded to the constructor of ImageDescription. + Allowed keys are: title, xlabel, ylabel, image. + """ + desc = self.add_new_desc_to_list(name, cfg, Desc=ImageDescription) #TODO: clean up Desc argument + if self.menu_settings.checkboxes["Open new plots"].isChecked(): + sub = self.mdi.findSubWindow(name) + if sub: + sub.pw.setImage(desc.data) #TODO lacks the list sync + else: + self.sig_make_new_image.emit(name, desc) + # Signal callbacks def on_make_new_plot(self, *args, **kwargs): self.make_subwin(MDISubPlot, *args, **kwargs) + def on_make_new_image(self, *args, **kwargs): + self.make_subwin(MDISubImage, *args, **kwargs) + def on_dclick_list_item(self, item): self.plot_single_item(item) @@ -188,7 +209,8 @@ class MainWindow(QMainWindow): for fn in fns: data = read_dict(fn) for k, v in data.items(): - self.add_new_desc_to_list(k, v) + Desc = ImageDescription if "image" in v else PlotDescription #TODO + self.add_new_desc_to_list(k, v, Desc=Desc) def on_file_save(self): @@ -206,8 +228,8 @@ class MainWindow(QMainWindow): # Plumbing - def add_new_desc_to_list(self, name, cfg): - desc = PlotDescription(name, **cfg) + def add_new_desc_to_list(self, name, cfg, Desc=PlotDescription): #TODO + desc = Desc(name, **cfg) self.lst.set(name, desc) return desc @@ -226,7 +248,8 @@ class MainWindow(QMainWindow): item.timestamps.access.update() item.set_alarm(False) name, desc = item.key, item.value - self.activate_or_make_subwin(MDISubPlot, name, desc) + MDISubType = MDISubImage if isinstance(desc, ImageDescription) else MDISubPlot #TODO + self.activate_or_make_subwin(MDISubType, name, desc) def plot_multiple_items(self, items): for i in items: diff --git a/grum/mdi/__init__.py b/grum/mdi/__init__.py index 4820247..e754999 100644 --- a/grum/mdi/__init__.py +++ b/grum/mdi/__init__.py @@ -1,5 +1,6 @@ from .mdiarea import MDIArea, MDIWindowMode from .mdisubplot import MDISubPlot, MDISubMultiPlot +from .mdisubimg import MDISubImage diff --git a/grum/mdi/mdisubimg.py b/grum/mdi/mdisubimg.py new file mode 100644 index 0000000..a3adce1 --- /dev/null +++ b/grum/mdi/mdisubimg.py @@ -0,0 +1,38 @@ +import pyqtgraph as pg +from .mdisubwin import MDISubWindow +from ..theme import pg_plot_style + + +class MDISubImage(MDISubWindow): + + def __init__(self, name, desc, *args, **kwargs): + super().__init__(name, *args, **kwargs) + self.pw = pw = pg.ImageView() + self.setWidget(pw) + + # connect to plot mouse-over event + pw.scene.sigMouseMoved.connect(self.on_hover) + + style = pg_plot_style() + + plot = desc.make_plot(self.pw, style) + self.plots = {name: plot} + + self.image = desc.data + + + def on_hover(self, event): + coord = self.pw.imageItem.mapFromScene(event) + x = coord.x() + y = coord.y() + x = int(x) + y = int(y) + try: + z = self.image[x, y] + except IndexError: + return + z = round(z, 3) + self.setToolTip(f"x = {x}\ny = {y}\nz = {z}") + + +