gui: basic scan support

This commit is contained in:
Sebastien Bourdeauducq 2015-07-21 17:23:32 +02:00
parent 1a0dc499dd
commit 179ca36d09
5 changed files with 150 additions and 8 deletions

View File

@ -87,17 +87,18 @@ def main():
d_ttl_dds = MonInj() d_ttl_dds = MonInj()
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify)) loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
atexit.register(lambda: loop.run_until_complete(d_ttl_dds.stop())) atexit.register(lambda: loop.run_until_complete(d_ttl_dds.stop()))
area.addDock(d_ttl_dds.dds_dock, "top")
area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
area.addDock(d_results, "above", d_ttl_dds.ttl_dock)
area.addDock(d_explorer, "above", d_results)
d_params = ParametersDock() d_params = ParametersDock()
area.addDock(d_params, "right", d_explorer)
loop.run_until_complete(d_params.sub_connect( loop.run_until_complete(d_params.sub_connect(
args.server, args.port_notify)) args.server, args.port_notify))
atexit.register(lambda: loop.run_until_complete(d_params.sub_close())) atexit.register(lambda: loop.run_until_complete(d_params.sub_close()))
area.addDock(d_ttl_dds.dds_dock, "top")
area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
area.addDock(d_results, "above", d_ttl_dds.ttl_dock)
area.addDock(d_params, "above", d_results)
area.addDock(d_explorer, "above", d_params)
d_schedule = ScheduleDock(schedule_ctl) d_schedule = ScheduleDock(schedule_ctl)
loop.run_until_complete(d_schedule.sub_connect( loop.run_until_complete(d_schedule.sub_connect(
args.server, args.port_notify)) args.server, args.port_notify))

View File

@ -8,6 +8,7 @@ from pyqtgraph import LayoutWidget
from artiq.protocols.sync_struct import Subscriber from artiq.protocols.sync_struct import Subscriber
from artiq.protocols import pyon from artiq.protocols import pyon
from artiq.gui.tools import DictSyncModel from artiq.gui.tools import DictSyncModel
from artiq.gui.scan import ScanController
class _ExplistModel(DictSyncModel): class _ExplistModel(DictSyncModel):
@ -93,7 +94,8 @@ _procty_to_entry = {
"BooleanValue": _BooleanEntry, "BooleanValue": _BooleanEntry,
"EnumerationValue": _EnumerationEntry, "EnumerationValue": _EnumerationEntry,
"NumberValue": _NumberEntry, "NumberValue": _NumberEntry,
"StringValue": _StringEntry "StringValue": _StringEntry,
"Scannable": ScanController
} }

137
artiq/gui/scan.py Normal file
View File

@ -0,0 +1,137 @@
from quamash import QtGui
from pyqtgraph import LayoutWidget
class _Range(LayoutWidget):
def __init__(self, global_min, global_max, global_step, unit):
LayoutWidget.__init__(self)
def apply_properties(spinbox):
if global_min is not None:
spinbox.setMinimum(global_min)
if global_max is not None:
spinbox.setMaximum(global_max)
if global_step is not None:
spinbox.setSingleStep(global_step)
if unit:
spinbox.setSuffix(" " + unit)
self.addWidget(QtGui.QLabel("Min:"), 0, 0)
self.min = QtGui.QDoubleSpinBox()
apply_properties(self.min)
self.addWidget(self.min, 0, 1)
self.addWidget(QtGui.QLabel("Max:"), 0, 2)
self.max = QtGui.QDoubleSpinBox()
apply_properties(self.max)
self.addWidget(self.max, 0, 3)
self.addWidget(QtGui.QLabel("#Points:"), 0, 4)
self.npoints = QtGui.QSpinBox()
self.npoints.setMinimum(2)
self.npoints.setValue(10)
self.addWidget(self.npoints, 0, 5)
def set_values(self, min, max, npoints):
self.min.setValue(min)
self.max.setValue(max)
self.npoints.setValue(npoints)
def get_values(self):
return {
"min": self.min.value(),
"max": self.max.value(),
"npoints": self.npoints.value()
}
class ScanController(LayoutWidget):
def __init__(self, procdesc):
LayoutWidget.__init__(self)
self.stack = QtGui.QStackedWidget()
self.addWidget(self.stack, 1, 0, colspan=4)
gmin, gmax = procdesc["global_min"], procdesc["global_max"]
gstep = procdesc["global_step"]
unit = procdesc["unit"]
self.v_noscan = QtGui.QDoubleSpinBox()
if gmin is not None:
self.v_noscan.setMinimum(gmin)
if gmax is not None:
self.v_noscan.setMaximum(gmax)
if gstep is not None:
self.v_noscan.setSingleStep(gstep)
if unit:
self.v_noscan.setSuffix(" " + unit)
self.v_noscan_gr = LayoutWidget()
self.v_noscan_gr.addWidget(QtGui.QLabel("Value:"), 0, 0)
self.v_noscan_gr.addWidget(self.v_noscan, 0, 1)
self.stack.addWidget(self.v_noscan_gr)
self.v_linear = _Range(gmin, gmax, gstep, unit)
self.stack.addWidget(self.v_linear)
self.v_random = _Range(gmin, gmax, gstep, unit)
self.stack.addWidget(self.v_random)
self.v_explicit = QtGui.QLineEdit()
self.v_explicit_gr = LayoutWidget()
self.v_explicit_gr.addWidget(QtGui.QLabel("Sequence:"), 0, 0)
self.v_explicit_gr.addWidget(self.v_explicit, 0, 1)
self.stack.addWidget(self.v_explicit_gr)
self.noscan = QtGui.QRadioButton("No scan")
self.linear = QtGui.QRadioButton("Linear")
self.random = QtGui.QRadioButton("Random")
self.explicit = QtGui.QRadioButton("Explicit")
radiobuttons = QtGui.QButtonGroup()
for n, b in enumerate([self.noscan, self.linear,
self.random, self.explicit]):
self.addWidget(b, 0, n)
radiobuttons.addButton(b)
b.toggled.connect(self.select_page)
if "default" in procdesc:
d = procdesc["default"]
if d["ty"] == "NoScan":
self.noscan.setChecked(True)
self.v_noscan.setValue(d["value"])
elif d["ty"] == "LinearScan":
self.linear.setChecked(True)
self.v_linear.set_values(d["min"], d["max"], d["step"])
elif d["ty"] == "RandomScan":
self.random.setChecked(True)
self.v_random.set_values(d["min"], d["max"], d["step"])
elif d["ty"] == "ExplicitScan":
self.explicit.setChecked(True)
self.v_explicit.insert(" ".join(
[str(x) for x in d["sequence"]]))
else:
self.noscan.setChecked(True)
def select_page(self):
if self.noscan.isChecked():
self.stack.setCurrentWidget(self.v_noscan_gr)
elif self.linear.isChecked():
self.stack.setCurrentWidget(self.v_linear)
elif self.random.isChecked():
self.stack.setCurrentWidget(self.v_random)
elif self.explicit.isChecked():
self.stack.setCurrentWidget(self.v_explicit_gr)
def get_argument_value(self):
if self.noscan.isChecked():
return {"ty": "NoScan", "value": self.v_noscan.value()}
elif self.linear.isChecked():
d = {"ty": "LinearScan"}
d.update(self.v_linear.get_values())
return d
elif self.random.isChecked():
d = {"ty": "RandomScan"}
d.update(self.v_random.get_values())
return d
elif self.explicit.isChecked():
sequence = [float(x) for x in self.v_explicit.text().split()]
return {"ty": "ExplicitScan", "sequence": sequence}

View File

@ -60,7 +60,6 @@ class RandomScan:
"min": self.min, "max": self.max, "npoints": self.npoints} "min": self.min, "max": self.max, "npoints": self.npoints}
class ExplicitScan: class ExplicitScan:
def __init__(self, sequence): def __init__(self, sequence):
self.sequence = sequence self.sequence = sequence
@ -109,7 +108,7 @@ class Scannable:
d["global_min"] = self.global_min d["global_min"] = self.global_min
d["global_max"] = self.global_max d["global_max"] = self.global_max
d["global_step"] = self.global_step d["global_step"] = self.global_step
d["unit"]= self.unit d["unit"] = self.unit
if hasattr(self, "default_value"): if hasattr(self, "default_value"):
d["default"] = self.default_value.describe() d["default"] = self.default_value.describe()
return d return d

View File

@ -9,6 +9,7 @@ class ArgumentsDemo(EnvExperiment):
["foo", "bar", "quux"], "foo")) ["foo", "bar", "quux"], "foo"))
self.attr_argument("number", NumberValue(42, unit="s", step=0.1)) self.attr_argument("number", NumberValue(42, unit="s", step=0.1))
self.attr_argument("string", StringValue("Hello World")) self.attr_argument("string", StringValue("Hello World"))
self.attr_argument("scan", Scannable(global_max=400, default=NoScan(325)))
def run(self): def run(self):
print(self.free_value) print(self.free_value)
@ -16,3 +17,5 @@ class ArgumentsDemo(EnvExperiment):
print(self.enum) print(self.enum)
print(self.number) print(self.number)
print(self.string) print(self.string)
for i in self.scan:
print(i)