Merge branch 'images' into 'master'
Images See merge request augustin_s/grum!8
This commit is contained in:
@ -22,11 +22,11 @@ Via the RPC server, new plots can be created and new data appended to existing p
|
|||||||
|
|
||||||
- `new_plot(name, cfg)`
|
- `new_plot(name, cfg)`
|
||||||
|
|
||||||
Creates a new plot named `name` in the grum list. The configuration dict `cfg` is used as arguments for the constructor of [`PlotDescription`](https://gitlab.psi.ch/augustin_s/grum/-/blob/master/grum/plotdesc.py#L4).
|
Creates a new plot named `name` in the grum list. The configuration dict `cfg` is used as arguments for the constructor of [`PlotDescription`](https://gitlab.psi.ch/augustin_s/grum/-/blob/master/grum/descs/plotdesc.py#L4).
|
||||||
|
|
||||||
- `append_data(name, point)`
|
- `append_data(name, point)`
|
||||||
|
|
||||||
Append data point to the plot named `name`. The new `point` is forwarded to [`PlotDescription.append()`](https://gitlab.psi.ch/augustin_s/grum/-/blob/master/grum/plotdesc.py#L18).
|
Append data point to the plot named `name`. The new `point` is forwarded to [`PlotDescription.append()`](https://gitlab.psi.ch/augustin_s/grum/-/blob/master/grum/descs/plotdesc.py#L18).
|
||||||
|
|
||||||
### Utility functions
|
### Utility functions
|
||||||
|
|
||||||
|
13
grum/descs/__init__.py
Normal file
13
grum/descs/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
from .desc import Description
|
||||||
|
from .imgdesc import ImageDescription
|
||||||
|
from .plotdesc import PlotDescription
|
||||||
|
|
||||||
|
|
||||||
|
DESC_TYPES = {
|
||||||
|
ImageDescription.get_type(): ImageDescription,
|
||||||
|
PlotDescription.get_type(): PlotDescription
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
23
grum/descs/desc.py
Normal file
23
grum/descs/desc.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
class Description:
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
res = {k: v for k, v in self.__dict__.items() if not k.startswith("_") and k != "name" and v is not None}
|
||||||
|
tn = self.get_type()
|
||||||
|
res.setdefault("type", tn)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_type(cls):
|
||||||
|
tn = cls.__name__
|
||||||
|
suffix = "Description"
|
||||||
|
if not tn.endswith(suffix):
|
||||||
|
raise ValueError(f'"{tn}" does not end with "{suffix}"')
|
||||||
|
tn = tn[:-len(suffix)]
|
||||||
|
tn = tn.casefold()
|
||||||
|
tn = tn or None
|
||||||
|
return tn
|
||||||
|
|
||||||
|
|
||||||
|
|
52
grum/descs/imgdesc.py
Normal file
52
grum/descs/imgdesc.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import numpy as np
|
||||||
|
import pyqtgraph as pg
|
||||||
|
from .desc import Description
|
||||||
|
|
||||||
|
|
||||||
|
class ImageDescription(Description):
|
||||||
|
|
||||||
|
def __init__(self, name, title=None, xlabel=None, ylabel=None, image=None, levels=None, cmap="viridis"):
|
||||||
|
self.name = name
|
||||||
|
self.title = title
|
||||||
|
self.xlabel = xlabel
|
||||||
|
self.ylabel = ylabel
|
||||||
|
self.image = image
|
||||||
|
self.levels = levels #TODO: might be better to use vmin and vmax
|
||||||
|
self.cmap = cmap
|
||||||
|
|
||||||
|
@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, levels=self.levels)
|
||||||
|
|
||||||
|
if self.title:
|
||||||
|
plotwidget.setTitle(self.title)
|
||||||
|
|
||||||
|
if self.xlabel:
|
||||||
|
plotwidget.getView().setLabel("bottom", self.xlabel)
|
||||||
|
|
||||||
|
if self.ylabel:
|
||||||
|
plotwidget.getView().setLabel("left", self.ylabel)
|
||||||
|
|
||||||
|
if self.cmap:
|
||||||
|
cm = pg.colormap.get(self.cmap)
|
||||||
|
plotwidget.setColorMap(cm)
|
||||||
|
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
|||||||
|
from .desc import Description
|
||||||
|
|
||||||
class PlotDescription:
|
|
||||||
|
class PlotDescription(Description):
|
||||||
|
|
||||||
def __init__(self, name, title=None, xlabel=None, ylabel=None, xs=None, ys=None):
|
def __init__(self, name, title=None, xlabel=None, ylabel=None, xs=None, ys=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -45,8 +47,4 @@ class PlotDescription:
|
|||||||
return res
|
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}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from .plotdesc import PlotDescription
|
from .descs import PlotDescription, ImageDescription
|
||||||
|
|
||||||
|
|
||||||
X = np.arange(100) / 10
|
X = np.arange(100) / 10
|
||||||
@ -31,4 +31,20 @@ for name, (xs, ys) in exampledata_raw.items():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
name = "image"
|
||||||
|
xdim = ydim = 100
|
||||||
|
size = xdim * ydim
|
||||||
|
shape = (xdim, ydim)
|
||||||
|
|
||||||
|
img = np.arange(size).reshape(shape) / size
|
||||||
|
img += np.random.random(shape) / 10
|
||||||
|
|
||||||
|
exampledata[name] = ImageDescription(
|
||||||
|
name,
|
||||||
|
image=img,
|
||||||
|
xlabel="x",
|
||||||
|
ylabel="y"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2,21 +2,27 @@ from PyQt5.QtCore import Qt, pyqtSignal
|
|||||||
from PyQt5.QtWidgets import QMainWindow, QSplitter
|
from PyQt5.QtWidgets import QMainWindow, QSplitter
|
||||||
|
|
||||||
from . import assets
|
from . import assets
|
||||||
|
from .descs import DESC_TYPES, Description, ImageDescription, PlotDescription
|
||||||
from .dictlist import DictList
|
from .dictlist import DictList
|
||||||
from .exampledata import exampledata
|
from .exampledata import exampledata
|
||||||
from .h5filedlg import open_h5_files_dialog, save_h5_file_dialog
|
from .h5filedlg import open_h5_files_dialog, save_h5_file_dialog
|
||||||
from .io import write_dict, read_dict
|
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 .menus import BarMenu
|
||||||
from .plotdesc import PlotDescription
|
|
||||||
from .rpc import RPCServerThread
|
from .rpc import RPCServerThread
|
||||||
from .shortcut import shortcut
|
from .shortcut import shortcut
|
||||||
from .webview import WebView
|
from .webview import WebView
|
||||||
|
|
||||||
|
|
||||||
|
DESC_TYPE_TO_MDI_SUB_TYPE = {
|
||||||
|
ImageDescription: MDISubImage,
|
||||||
|
PlotDescription: MDISubPlot
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
|
|
||||||
sig_make_new_plot = pyqtSignal(str, PlotDescription)
|
sig_make_new_subwin = pyqtSignal(str, Description)
|
||||||
|
|
||||||
def __init__(self, *args, title="grum", host="localhost", port=8000, offline=False, add_examples=False, window_mode=MDIWindowMode.MULTI, **kwargs):
|
def __init__(self, *args, title="grum", host="localhost", port=8000, offline=False, add_examples=False, window_mode=MDIWindowMode.MULTI, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -84,12 +90,13 @@ class MainWindow(QMainWindow):
|
|||||||
if not offline:
|
if not offline:
|
||||||
self.rst = rst = RPCServerThread(host, port, doc_title_suffix=title)
|
self.rst = rst = RPCServerThread(host, port, doc_title_suffix=title)
|
||||||
rst.start()
|
rst.start()
|
||||||
|
rst.server.register_function(self.new_image)
|
||||||
rst.server.register_function(self.new_plot)
|
rst.server.register_function(self.new_plot)
|
||||||
rst.server.register_function(self.append_data)
|
rst.server.register_function(self.append_data)
|
||||||
rst.server.register_function(self.extend_data)
|
rst.server.register_function(self.extend_data)
|
||||||
rst.server.register_function(self.set_data)
|
rst.server.register_function(self.set_data)
|
||||||
|
|
||||||
self.sig_make_new_plot.connect(self.on_make_new_plot)
|
self.sig_make_new_subwin.connect(self.on_make_new_subwin)
|
||||||
|
|
||||||
|
|
||||||
def keyPressEvent(self, event):
|
def keyPressEvent(self, event):
|
||||||
@ -99,16 +106,30 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Remote API calls
|
# Remote API calls
|
||||||
|
|
||||||
|
def new_image(self, name, cfg):
|
||||||
|
"""
|
||||||
|
Create a new image <name> using the configuration dict <cfg>.
|
||||||
|
The configuration is forwarded to the constructor of ImageDescription.
|
||||||
|
Allowed keys are: title, xlabel, ylabel, image.
|
||||||
|
"""
|
||||||
|
desc = self.add_new_desc_to_list(ImageDescription, name, cfg)
|
||||||
|
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_subwin.emit(name, desc)
|
||||||
|
|
||||||
def new_plot(self, name, cfg):
|
def new_plot(self, name, cfg):
|
||||||
"""
|
"""
|
||||||
Create a new plot <name> using the configuration dict <cfg>.
|
Create a new plot <name> using the configuration dict <cfg>.
|
||||||
The configuration is forwarded to the constructor of PlotDescription.
|
The configuration is forwarded to the constructor of PlotDescription.
|
||||||
Allowed keys are: title, xlabel, ylabel, xs, ys.
|
Allowed keys are: title, xlabel, ylabel, xs, ys.
|
||||||
"""
|
"""
|
||||||
desc = self.add_new_desc_to_list(name, cfg)
|
desc = self.add_new_desc_to_list(PlotDescription, name, cfg)
|
||||||
if self.menu_settings.checkboxes["Open new plots"].isChecked():
|
if self.menu_settings.checkboxes["Open new plots"].isChecked():
|
||||||
if not self.mdi.findSubWindow(name):
|
if not self.mdi.findSubWindow(name):
|
||||||
self.sig_make_new_plot.emit(name, desc)
|
self.sig_make_new_subwin.emit(name, desc)
|
||||||
|
|
||||||
def append_data(self, name, point):
|
def append_data(self, name, point):
|
||||||
"""
|
"""
|
||||||
@ -143,8 +164,10 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Signal callbacks
|
# Signal callbacks
|
||||||
|
|
||||||
def on_make_new_plot(self, *args, **kwargs):
|
def on_make_new_subwin(self, name, desc):
|
||||||
self.make_subwin(MDISubPlot, *args, **kwargs)
|
DescType = type(desc)
|
||||||
|
MDISubType = DESC_TYPE_TO_MDI_SUB_TYPE[DescType]
|
||||||
|
self.make_subwin(MDISubType, name, desc)
|
||||||
|
|
||||||
def on_dclick_list_item(self, item):
|
def on_dclick_list_item(self, item):
|
||||||
self.plot_single_item(item)
|
self.plot_single_item(item)
|
||||||
@ -187,8 +210,10 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
for fn in fns:
|
for fn in fns:
|
||||||
data = read_dict(fn)
|
data = read_dict(fn)
|
||||||
for k, v in data.items():
|
for name, cfg in data.items():
|
||||||
self.add_new_desc_to_list(k, v)
|
tn = cfg.pop("type")
|
||||||
|
DescType = DESC_TYPES[tn]
|
||||||
|
self.add_new_desc_to_list(DescType, name, cfg)
|
||||||
|
|
||||||
|
|
||||||
def on_file_save(self):
|
def on_file_save(self):
|
||||||
@ -206,8 +231,8 @@ class MainWindow(QMainWindow):
|
|||||||
|
|
||||||
# Plumbing
|
# Plumbing
|
||||||
|
|
||||||
def add_new_desc_to_list(self, name, cfg):
|
def add_new_desc_to_list(self, DescType, name, cfg):
|
||||||
desc = PlotDescription(name, **cfg)
|
desc = DescType(name, **cfg)
|
||||||
self.lst.set(name, desc)
|
self.lst.set(name, desc)
|
||||||
return desc
|
return desc
|
||||||
|
|
||||||
@ -226,19 +251,22 @@ class MainWindow(QMainWindow):
|
|||||||
item.timestamps.access.update()
|
item.timestamps.access.update()
|
||||||
item.set_alarm(False)
|
item.set_alarm(False)
|
||||||
name, desc = item.key, item.value
|
name, desc = item.key, item.value
|
||||||
self.activate_or_make_subwin(MDISubPlot, name, desc)
|
DescType = type(desc)
|
||||||
|
MDISubType = DESC_TYPE_TO_MDI_SUB_TYPE[DescType]
|
||||||
|
self.activate_or_make_subwin(MDISubType, name, desc)
|
||||||
|
|
||||||
def plot_multiple_items(self, items):
|
def plot_multiple_items(self, items):
|
||||||
for i in items:
|
for i in items:
|
||||||
i.timestamps.access.update()
|
i.timestamps.access.update()
|
||||||
i.set_alarm(False)
|
i.set_alarm(False)
|
||||||
|
items = (i for i in items if isinstance(i.value, PlotDescription)) #TODO: for now, only overlay plots
|
||||||
descs = {i.key: i.value for i in items}
|
descs = {i.key: i.value for i in items}
|
||||||
names = descs.keys()
|
names = descs.keys()
|
||||||
name = " | ".join(names)
|
name = " | ".join(names)
|
||||||
self.activate_or_make_subwin(MDISubMultiPlot, name, descs)
|
self.activate_or_make_subwin(MDISubMultiPlot, name, descs)
|
||||||
|
|
||||||
|
|
||||||
#TODO: the following two could be methods to MDIArea?
|
#TODO: the following two could be methods of MDIArea?
|
||||||
|
|
||||||
def activate_or_make_subwin(self, MDISubType, name, *args, **kwargs):
|
def activate_or_make_subwin(self, MDISubType, name, *args, **kwargs):
|
||||||
sub = self.mdi.findSubWindow(name)
|
sub = self.mdi.findSubWindow(name)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
from .mdiarea import MDIArea, MDIWindowMode
|
from .mdiarea import MDIArea, MDIWindowMode
|
||||||
from .mdisubplot import MDISubPlot, MDISubMultiPlot
|
from .mdisubplot import MDISubPlot, MDISubMultiPlot
|
||||||
|
from .mdisubimg import MDISubImage
|
||||||
|
|
||||||
|
|
||||||
|
38
grum/mdi/mdisubimg.py
Normal file
38
grum/mdi/mdisubimg.py
Normal file
@ -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(view=pg.PlotItem()) # for axis ticks and labels, view needs to be a PlotItem
|
||||||
|
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}")
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -4,12 +4,17 @@ from PyQt5.QtWidgets import QMdiSubWindow
|
|||||||
from .. import assets
|
from .. import assets
|
||||||
|
|
||||||
|
|
||||||
|
SUB_WIN_WIDTH = 640
|
||||||
|
SUB_WIN_HEIGHT = 480
|
||||||
|
|
||||||
|
|
||||||
class MDISubWindow(QMdiSubWindow):
|
class MDISubWindow(QMdiSubWindow):
|
||||||
|
|
||||||
def __init__(self, title, *args, **kwargs):
|
def __init__(self, title, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.setWindowTitle(title)
|
self.setWindowTitle(title)
|
||||||
self.setWindowIcon(assets.char())
|
self.setWindowIcon(assets.char())
|
||||||
|
self.resize(SUB_WIN_WIDTH, SUB_WIN_HEIGHT)
|
||||||
|
|
||||||
# without this, the SubWindow is not removed from the subWindowList
|
# without this, the SubWindow is not removed from the subWindowList
|
||||||
self.setAttribute(Qt.WA_DeleteOnClose)
|
self.setAttribute(Qt.WA_DeleteOnClose)
|
||||||
|
@ -14,7 +14,7 @@ from grum.mainwin import MainWindow
|
|||||||
from grum.mdi import MDIArea, MDISubMultiPlot, MDISubPlot
|
from grum.mdi import MDIArea, MDISubMultiPlot, MDISubPlot
|
||||||
from grum.menus import BarMenu
|
from grum.menus import BarMenu
|
||||||
from grum.menus.rclickmenu import RClickMenu
|
from grum.menus.rclickmenu import RClickMenu
|
||||||
from grum.plotdesc import PlotDescription
|
from grum.descs import Description, PlotDescription
|
||||||
from grum.rpc import RPCServerThread
|
from grum.rpc import RPCServerThread
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ class TestMainWin:
|
|||||||
|
|
||||||
for key in mw.lst.lst.items:
|
for key in mw.lst.lst.items:
|
||||||
assert isinstance(mw.lst.lst.get(key), DictListItem)
|
assert isinstance(mw.lst.lst.get(key), DictListItem)
|
||||||
assert isinstance(mw.lst.lst.get(key).value, PlotDescription)
|
assert isinstance(mw.lst.lst.get(key).value, Description)
|
||||||
|
|
||||||
assert isinstance(mw.lst.menu, RClickMenu)
|
assert isinstance(mw.lst.menu, RClickMenu)
|
||||||
assert isinstance(mw.menu_settings, BarMenu)
|
assert isinstance(mw.menu_settings, BarMenu)
|
||||||
@ -65,7 +65,7 @@ class TestMainWin:
|
|||||||
xlabel = "xlabel"
|
xlabel = "xlabel"
|
||||||
ylabel = "ylabel"
|
ylabel = "ylabel"
|
||||||
cfg = {"title": title, "xlabel": xlabel, "ylabel": ylabel}
|
cfg = {"title": title, "xlabel": xlabel, "ylabel": ylabel}
|
||||||
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
|
spy_sig_make_new_subwin = QSignalSpy(mw.sig_make_new_subwin)
|
||||||
|
|
||||||
mw.new_plot(name, cfg=cfg)
|
mw.new_plot(name, cfg=cfg)
|
||||||
|
|
||||||
@ -76,28 +76,28 @@ class TestMainWin:
|
|||||||
assert mw.lst.lst.get(name).value.ylabel == ylabel
|
assert mw.lst.lst.get(name).value.ylabel == ylabel
|
||||||
|
|
||||||
assert mw.menu_settings.checkboxes["Open new plots"].isChecked()
|
assert mw.menu_settings.checkboxes["Open new plots"].isChecked()
|
||||||
assert len(spy_sig_make_new_plot) == 1 # assert called once
|
assert len(spy_sig_make_new_subwin) == 1 # assert called once
|
||||||
assert spy_sig_make_new_plot[0][0] == name # assert called with name
|
assert spy_sig_make_new_subwin[0][0] == name # assert called with name
|
||||||
assert isinstance(spy_sig_make_new_plot[0][1], PlotDescription)
|
assert isinstance(spy_sig_make_new_subwin[0][1], PlotDescription)
|
||||||
|
|
||||||
mw.menu_settings.checkboxes["Open new plots"].setChecked(False)
|
mw.menu_settings.checkboxes["Open new plots"].setChecked(False)
|
||||||
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == False
|
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == False
|
||||||
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
|
spy_sig_make_new_subwin = QSignalSpy(mw.sig_make_new_subwin)
|
||||||
|
|
||||||
mw.new_plot("new_name", cfg)
|
mw.new_plot("new_name", cfg)
|
||||||
|
|
||||||
assert len(spy_sig_make_new_plot) == 0 # assert not called
|
assert len(spy_sig_make_new_subwin) == 0 # assert not called
|
||||||
|
|
||||||
mw.menu_settings.checkboxes["Open new plots"].setChecked(True)
|
mw.menu_settings.checkboxes["Open new plots"].setChecked(True)
|
||||||
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == True
|
assert mw.menu_settings.checkboxes["Open new plots"].isChecked() == True
|
||||||
spy_sig_make_new_plot = QSignalSpy(mw.sig_make_new_plot)
|
spy_sig_make_new_subwin = QSignalSpy(mw.sig_make_new_subwin)
|
||||||
new_name_item = mw.lst.lst.get("new_name")
|
new_name_item = mw.lst.lst.get("new_name")
|
||||||
sub = MDISubPlot("new_name", new_name_item.value)
|
sub = MDISubPlot("new_name", new_name_item.value)
|
||||||
mw.mdi.add(sub)
|
mw.mdi.add(sub)
|
||||||
|
|
||||||
mw.new_plot("new_name", cfg)
|
mw.new_plot("new_name", cfg)
|
||||||
|
|
||||||
assert len(spy_sig_make_new_plot) == 0 # assert not called
|
assert len(spy_sig_make_new_subwin) == 0 # assert not called
|
||||||
|
|
||||||
|
|
||||||
def test_append_data(self):
|
def test_append_data(self):
|
||||||
@ -122,17 +122,19 @@ class TestMainWin:
|
|||||||
assert sine_item.set_alarm.call_args[0][0] == False
|
assert sine_item.set_alarm.call_args[0][0] == False
|
||||||
|
|
||||||
|
|
||||||
def test_on_make_new_plot(self):
|
def test_on_make_new_subwin(self):
|
||||||
mw = self.mw
|
mw = self.mw
|
||||||
|
|
||||||
mw.make_subwin = mock.MagicMock()
|
mw.make_subwin = mock.MagicMock()
|
||||||
|
|
||||||
args = (1, 2, "name")
|
name = "test"
|
||||||
kwargs = {"title": "plot_title"}
|
cfg = {"title": "title"}
|
||||||
|
|
||||||
mw.on_make_new_plot(args, kwargs)
|
desc = PlotDescription(name, *cfg)
|
||||||
|
|
||||||
mw.make_subwin.assert_called_once_with(MDISubPlot, args, kwargs)
|
mw.on_make_new_subwin(name, desc)
|
||||||
|
|
||||||
|
mw.make_subwin.assert_called_once_with(MDISubPlot, name, desc)
|
||||||
|
|
||||||
|
|
||||||
def test_on_dclick_list_item(self):
|
def test_on_dclick_list_item(self):
|
||||||
|
@ -6,7 +6,7 @@ import pyqtgraph as pg
|
|||||||
from grum import theme
|
from grum import theme
|
||||||
from grum.mainwin import MainWindow
|
from grum.mainwin import MainWindow
|
||||||
from grum.mdi.mdisubplot import MDISubPlot
|
from grum.mdi.mdisubplot import MDISubPlot
|
||||||
from grum.plotdesc import PlotDescription
|
from grum.descs import PlotDescription
|
||||||
from grum.theme import pg_plot_style
|
from grum.theme import pg_plot_style
|
||||||
|
|
||||||
|
|
||||||
@ -78,6 +78,7 @@ def test_to_dict():
|
|||||||
"xs": [1, 2],
|
"xs": [1, 2],
|
||||||
"ylabel": "plot_ylabel",
|
"ylabel": "plot_ylabel",
|
||||||
"ys": [3, 4],
|
"ys": [3, 4],
|
||||||
|
"type": "plot"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user