Usage¶
Starting the application¶
After installation, launch the application from the command line:
stoner-measurement
Or from Python:
from stoner_measurement.main import main
main()
Application layout¶
The main window is split into three panels:
Left panel (25 %) — Instrument / plugin list and sequence builder. Drag instruments into the sequence list to build a measurement sequence.
Central panel (50 %) — Live PyQtGraph plotting area. Data points produced by each sequence step are plotted here in real time.
Right panel (25 %) — Tabbed configuration area. Each loaded plugin contributes a tab with its own configuration controls.
Building and running a sequence¶
Select an instrument in the left panel and click Add Step.
Repeat for each step you need.
Configure each step via the corresponding tab in the right panel.
Click Run to start the sequence.
Writing a plugin¶
All measurement plugins inherit from
BasePlugin. Choose the
appropriate subclass for your plugin type and register it via the
stoner_measurement.plugins entry-point group in your package’s
pyproject.toml:
[project.entry-points."stoner_measurement.plugins"]
my_instrument = "my_package.my_plugin:MyPlugin"
Plugin types¶
Measurement trace plugin — subclass
TracePlugin:
Required:
nameandexecute()— a generator that yields(x, y)tuples for each measured point.Optionally override
connect(),configure(), anddisconnect()to manage hardware connections.
State-control plugin — subclass
StateControlPlugin:
Required:
name,state_name,units,set_state(),get_state(), andis_at_target().The sequence engine drives this plugin over a scan defined by
scan_generator. Other steps can be nested beneath it in the sequence tree.
Monitor plugin — subclass
MonitorPlugin:
Required:
name,quantity_names,units, andread().
Transform plugin — subclass
TransformPlugin:
Required:
name,required_inputs,output_names, andtransform().
Minimal example¶
The following shows the minimum required implementation for a trace plugin:
from stoner_measurement.plugins.trace import TracePlugin
class ThermometerPlugin(TracePlugin):
@property
def name(self):
return "Thermometer"
def execute(self, parameters):
for reading in self._hardware.read(parameters.get("samples", 10)):
yield reading.time, reading.temperature
Optional UI integration¶
Plugins can hook into the main window UI by overriding any of the following methods.
config_tabs(parent=None) → list[tuple[str, QWidget]]¶
Returns a list of (tab_title, widget) pairs. Each pair becomes one tab
in the right-hand configuration panel.
The default implementation wraps config_widget() in a single-element
list using name as the tab title. Override config_tabs() directly
when a plugin needs more than one tab or a custom tab title.
def config_tabs(self, parent=None):
settings = self.config_widget(parent=parent)
about = QLabel("My plugin v1.0", parent)
return [
("MyPlugin \u2013 Settings", settings),
("MyPlugin \u2013 About", about),
]
config_widget(parent=None) → QWidget¶
Returns a single QWidget. Used by the default config_tabs()
implementation — override this when a single configuration tab is
sufficient.
monitor_widget(parent=None) → QWidget | None¶
Returns an optional live-status widget shown in the left dock panel
Monitoring section whilst the plugin is registered. Return None (the
default) if no monitoring widget is needed.
def monitor_widget(self, parent=None):
self._status_label = QLabel("Idle", parent)
return self._status_label
All TracePlugin and
StateControlPlugin
subclasses can also optionally provide custom configuration tabs by
overriding:
_plugin_config_tabs()— return aQWidgetthat appears as the Settings configuration tab._about_html()— return an HTML string that appears as an About configuration tab.