QScanner#

class QPolargraph.QScanner.QScanner(*args, configdir=None, fake=False, pattern=None, **kwargs)[source]#

Bases: QMainWindow

Application framework for a polargraph scanner.

Builds the UI programmatically, wires up a QPolargraphWidget and a QScanPatternWidget, and provides a live pyqtgraph display of the scan trajectory and current belt geometry. Intended to be subclassed for experiment-specific scanner applications.

Class Attributes#

SCAN_PATTERNtype

QScanPattern subclass to instantiate as the scan pattern. Default: PolarScan. Subclasses override this to select a different scan pattern:

class QMyScanner(QScanner):
    SCAN_PATTERN = RasterScan
SCAN_WIDGETtype

QScanPatternWidget subclass to instantiate as the scan controls widget. Default: QScanPatternWidget. Subclasses override this to provide a custom controls widget:

class QMyScanner(QScanner):
    SCAN_WIDGET = TarzanScanWidget

Properties#

configdirstr

Directory for storing instrument configuration. Defaults to ~/.<ClassName> where ClassName is the name of the concrete subclass: each subclass gets its own config directory.

showStatus(message)[source]#

Display message on the status bar.

plotData(x, y, hue)[source]#

Add scatter points at (x, y) colored by hue in [0, 1].

Signals()#
-------
dataReady(dict)#

Emitted at each position during a scan. The base class emits {'t': float, 'x': float, 'y': float} where t is a time.monotonic() timestamp [s] and x, y are Cartesian coordinates [m]. Subclasses may override _onDataReady() to merge in additional measurement fields before emitting. Because _onDataReady runs on the GUI thread, instrument reads there should be fast and non-blocking; for tight timing call the instrument inside _onMeasure() instead (runs in the polargraph device thread):

def _onDataReady(self, pos: np.ndarray) -> None:
    self.dataReady.emit(
        {'t': float(pos[2]), 'x': float(pos[0]),
         'y': float(pos[1])}
        | self.instrument.acquire())

A sequence of emitted dicts can be collected directly into a pandas.DataFrame:

rows = []
scanner.dataReady.connect(rows.append)
# after scan:
df = pd.DataFrame(rows)
dataReady#
SCAN_PATTERN#

alias of PolarScan

SCAN_WIDGET#

alias of QScanPatternWidget

setupPolargraph(fake)[source]#
Return type:

None

setupScanner(pattern)[source]#
Return type:

None

configure(configdir)[source]#
Return type:

None

setupUi()[source]#
Return type:

None

connectSignals()[source]#
Return type:

None

updatePlot()[source]#
Return type:

None

plotTrajectory()[source]#
Return type:

None

plotBelt(data=None)[source]#
Return type:

None

toggleScan()[source]#

Emit the toggle signal to start, pause, or resume the scan.

Routes through _toggle so the call is delivered as a QueuedConnection when the scan pattern lives in a worker thread (real hardware), or as a DirectConnection in tests.

Return type:

None

plotData(x, y, hue, saturation=1.0)[source]#

Add scatter points to the data plot.

Parameters:
  • x (array-like) – Horizontal coordinates [m].

  • y (array-like) – Vertical coordinates [m].

  • hue (array-like) – Color values in [0, 1] (HSV hue).

  • saturation (array-like, optional) – Saturation values in [0, 1] (HSV saturation). Default: 1.0 (fully saturated). Low saturation appears white, high saturation gives the pure hue color.

Return type:

None

saveSettings()[source]#
Return type:

None

restoreSettings()[source]#
Return type:

None

showStatus(message)[source]#

Display a message on the status bar.

Return type:

None

closeEvent(event)[source]#
Return type:

None

classmethod example()[source]#

Launch the scanner application.

Creates a QApplication, instantiates the scanner, shows it, and runs the event loop. Intended to be called from __main__ in subclass modules:

if __name__ == '__main__':
    QMyScanner.example()

Accepts the following command-line flags:

Return type:

None

-f / --fake

Force use of the fake instrument.

-r / --raster

Use RasterScan.

-p / --polar

Use PolarScan (default).

-t / --tarzan

Use TarzanScan.