Quick start#

Launch the scanner application#

python -m QPolargraph
# or, after installation:
qpolargraph

Pass -f / --fake to run with a simulated instrument (no hardware required):

qpolargraph --fake

The application opens a live plot showing the belt geometry and the scan trajectory. Use Scan to start a polar-arc sweep, or Home / Center to move the payload to the home or centre position.

Embed in your own application#

Subclass QScanner to add experiment-specific data acquisition. Override _onDataReady() to merge in additional measurement fields before emitting dataReady:

from QPolargraph.QScanner import QScanner
import numpy as np


class MyScanner(QScanner):

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


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

The dataReady signal emits a dict at each scan position. A sequence of emitted dicts can be collected directly into a pandas.DataFrame:

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

Use a different scan pattern#

Set the SCAN_PATTERN class attribute to any QScanPattern subclass:

from QPolargraph.QScanner import QScanner
from QPolargraph.patterns.RasterScan import RasterScan


class MyScanner(QScanner):
    SCAN_PATTERN = RasterScan


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

Control the hardware directly#

from qtpy.QtCore import QCoreApplication
from QPolargraph.hardware.Polargraph import Polargraph
import sys

app = QCoreApplication(sys.argv)
pg = Polargraph(ell=0.8, y0=0.15).find()   # auto-detects USB port
print(pg.position)                           # (x, y, running) in metres
pg.moveTo(0.0, 0.3)
while pg.running():
    pass
pg.release()