def prepare_graphics(self, container): canvas = Canvas() container.set_widget(canvas) self.text0 = Text('') self.text0.pos = -0.15, 0 canvas.add_item(self.text0)
def prepare_graphics(self, container): self.plt = pg.PlotWidget() self.plots = [] self.canvas = Canvas() self.cursors = [] self.targets = [] for i in np.arange(config['numbands']): # Plotting self.plots.append( self.plt.plot([], [], pen=pg.intColor(i, hues=config['numbands']))) # Feedback self.cursors.append( Circle(0.1, color=pg.intColor(i, hues=config['numbands']))) self.cursors[i].pos = self.cursorx[i], 0 # evenly space self.canvas.add_item(self.cursors[i]) # Training self.targets.append(Circle(0.1, color='#32b124')) self.targets[i].pos = self.cursorx[i], .5 # evenly space self.canvas.add_item(self.targets[i]) self.plt.setRange(yRange=(0, .2), xRange=(0, 200)) # Qt layout = QtGui.QGridLayout() container.setLayout(layout) layout.addWidget(self.canvas, 0, 0) # 1st column layout.addWidget(self.plt, 0, 1) # 2nd column
def prepare_graphics(self, container): """Define the GUI by using Items etc. """ self.canvas = Canvas() self.text = Text(text='', color='red') self.canvas.add_item(self.text) container.set_widget(self.canvas)
def prepare_graphics(self, container): self.canvas = Canvas() self.cursor = Circle(0.05, color='#aa1212') self.target = Circle(0.1, color='#32b124') self.canvas.add_item(self.target) self.canvas.add_item(self.cursor) self.canvas.add_item(Cross()) container.set_widget(self.canvas)
class Exertion(Task): def __init__(self, pipeline): super().__init__() self.pipeline = pipeline def prepare_design(self, design): block = design.add_block() for trial in [True] * 2: block.add_trial() def prepare_storage(self, storage): self.writer = storage.create_task('Exertiontask_' + time.strftime("%Y%m%d-%H%M%S")) def prepare_graphics(self, container): self.countdown = Canvas() self.countdowntext = Text("Flex!") self.countdown.add_item(self.countdowntext) container.set_widget(self.countdown) def prepare_daq(self, daqstream): self.daqstream = daqstream self.daqstream.start() self.timer = Counter(10) self.timer.timeout.connect(self.finish_trial) def run_trial(self, trial): self.timer.reset() self.pipeline.clear() self.connect(self.daqstream.updated, self.update) def update(self, data): self.integratedEMG = self.pipeline.process(data)[1:] self.timer.increment() def finish_trial(self): self.trial.attrs['Exertion'] = self.integratedEMG self.writer.write(self.trial) self.disconnect(self.daqstream.updated, self.update) self.next_trial() def finish(self): self.daqstream.stop() self.finished.emit() def key_press(self, key): if key == util.key_escape: self.finish() if key == util.key_q: sys.exit() else: super().key_press(key)
def test_container_layout(): layout = QtWidgets.QVBoxLayout() layout.addWidget(QtWidgets.QPushButton()) layout.addWidget(Canvas()) c = Container() c.set_layout(layout)
def run(self, *tasks): """Run the experimental tasks.""" if self.subject is None: self.configure() self.screen.key_pressed.connect(self.key_press) # screen to show "Ready" between tasks self.confirm_screen = Canvas(draw_border=False) self.confirm_screen.add_item(Text("Ready (enter to start)")) self.storage.subject_id = self.subject self.tasks = tasks self.current_task = None self.task_iter = iter(self.tasks) self._task_finished() self.screen.run()
def prepare_graphics(self, container): self.text0 = Text('Master: 0') self.text0.pos = -0.2, 0.5 self.text1 = Text('Daq 1: 0') self.text1.pos = -0.2, 0 self.text2 = Text('Daq 2: 0') self.text2.pos = -0.2, -0.5 canvas = Canvas() canvas.add_item(self.text0) canvas.add_item(self.text1) canvas.add_item(self.text2) container.set_widget(canvas)
def prepare_graphics(self, container): canvas = Canvas() container.set_widget(canvas) # create a couple text items that tick with each daq update self.text1 = Text('0') self.text1.pos = -0.5, 0 canvas.add_item(self.text1) self.text2 = Text('0') self.text2.pos = 0.5, 0 canvas.add_item(self.text2) # counters keeping track of the updates self.counter1 = Counter(100, reset_on_timeout=False) self.counter2 = Counter(100, reset_on_timeout=False) # stop updating when the faster DAQ has updated 100 times self.counter1.timeout.connect(self.done)
class CursorFollowing(Task): # TODO split this into two tasks (a "training" task and a "practice" task). # This would involve storing the RLS weights and loading them for the # practice task. Probably a good idea to write a simple cursor interface # class to share common code between the two tasks. target_dist = 0.8 def __init__(self, pipeline): super(CursorFollowing, self).__init__() self.pipeline = pipeline def prepare_design(self, design): d = self.target_dist target_positions = [(d, 0), (0, d), (-d, 0), (0, -d), (0, 0)] for training in [True, False]: block = design.add_block() for x, y in target_positions: block.add_trial(attrs={ 'target_x': x, 'target_y': y, 'training': training }) block.shuffle() def prepare_graphics(self, container): self.canvas = Canvas() self.cursor = Circle(0.05, color='#aa1212') self.target = Circle(0.1, color='#32b124') self.canvas.add_item(self.target) self.canvas.add_item(self.cursor) self.canvas.add_item(Cross()) container.set_widget(self.canvas) def prepare_daq(self, daqstream): self.daqstream = daqstream self.daqstream.start() self.timer = Counter(50) self.timer.timeout.connect(self.finish_trial) def run_trial(self, trial): if not trial.attrs['training']: self.target.color = '#3224b1' self._reset() self.target.pos = trial.attrs['target_x'], trial.attrs['target_y'] self.target.show() self.pipeline.clear() self.connect(self.daqstream.updated, self.update) def update(self, data): xhat = self.pipeline.process(data) self.cursor.pos = xhat target_pos = numpy.array( [self.trial.attrs['target_x'], self.trial.attrs['target_y']]) if self.trial.attrs['training']: self.pipeline.named_blocks['RLSMapping'].update(target_pos) if self.cursor.collides_with(self.target): self.finish_trial() self.timer.increment() def finish_trial(self): self.disconnect(self.daqstream.updated, self.update) self._reset() self.next_trial() def _reset(self): self.cursor.pos = 0, 0 self.timer.reset() self.target.hide() def finish(self): self.daqstream.stop() def key_press(self, key): if key == util.key_escape: self.finish() else: super().key_press(key)
def test_canvas(): c = Canvas() c.add_item(Circle(0.1)) c.add_item(Circle(0.1).qitem)
class PartialPowers(Task): def __init__(self, pipeline): super().__init__() self.pipeline = pipeline def prepare_design(self, design): # yikes... evenly space along the horizontal self.cursorx = [(i + 1.) * 2 / (config['numbands'] + 1.) - 1. for i in np.arange(config['numbands'])] # returns array of all possible combinations self.active_targets = np.unpackbits( np.arange(np.power(2, config['numbands']), dtype=np.uint8)[:, None], axis=1)[:, -config['numbands']:] / 2 + .25 for training in [True] * 10: block = design.add_block() for active in self.active_targets: block.add_trial(attrs={ 'active_targets': active, 'training': training }) block.shuffle() def prepare_storage(self, storage): self.writer = storage.create_task('training task_' + time.strftime("%Y%m%d-%H%M%S")) def prepare_graphics(self, container): self.plt = pg.PlotWidget() self.plots = [] self.canvas = Canvas() self.cursors = [] self.targets = [] for i in np.arange(config['numbands']): # Plotting self.plots.append( self.plt.plot([], [], pen=pg.intColor(i, hues=config['numbands']))) # Feedback self.cursors.append( Circle(0.1, color=pg.intColor(i, hues=config['numbands']))) self.cursors[i].pos = self.cursorx[i], 0 # evenly space self.canvas.add_item(self.cursors[i]) # Training self.targets.append(Circle(0.1, color='#32b124')) self.targets[i].pos = self.cursorx[i], .5 # evenly space self.canvas.add_item(self.targets[i]) self.plt.setRange(yRange=(0, .2), xRange=(0, 200)) # Qt layout = QtGui.QGridLayout() container.setLayout(layout) layout.addWidget(self.canvas, 0, 0) # 1st column layout.addWidget(self.plt, 0, 1) # 2nd column def prepare_daq(self, daqstream): self.daqstream = daqstream self.daqstream.start() self.timer = Counter(100) self.timer.timeout.connect(self.finish_trial) def run_trial(self, trial): # change the color of the target cursor depending if training if not trial.attrs['training']: for i in np.arange(config['numbands']): self.targets[i].color = '#3224b1' self._reset() # set the target positions for i in np.arange(config['numbands']): self.targets[i].pos = self.cursorx[i], trial.attrs[ 'active_targets'][i] self.targets[i].show() self.pipeline.clear() self.connect(self.daqstream.updated, self.update) def update(self, data): self.weights = np.multiply([0.33271298928451853, 0.62291817090414547], .2) self.differencefactor = 0.1 self.integratedEMG = self.pipeline.process(data) self.windoweddata = self.integratedEMG.pop(0) for i in np.arange(config['numbands']): # self.plots[i].setData(self.freq, self.powers[:, i]) self.cursors[i].y = self.integratedEMG[i] / self.weights[ i] - self.differencefactor * np.sum( np.delete(self.integratedEMG, i) / np.delete(self.weights, i)) target_pos = np.array(self.trial.attrs['active_targets']).flatten() if all( cursor.collides_with(self.targets[i]) for i, cursor in enumerate(self.cursors)): self.finish_trial() self.timer.increment() def finish_trial(self): self.trial.attrs['final_cursor_pos'] = [ self.cursors[i].pos[1] for i in np.arange(config['numbands']) ] self.trial.attrs['time'] = self.timer.count self.trial.attrs['timeout'] = self.trial.attrs['time'] < 1 self.trial.add_array( 'windowedEMG', data=self.windoweddata) # TODO: complain to kenny about this self.writer.write(self.trial) self.disconnect(self.daqstream.updated, self.update) self._reset() self.next_trial() def _reset(self): for i in np.arange(config['numbands']): self.cursors[i].pos = self.cursorx[i], 0 # evenly space self.targets[i].hide() self.timer.reset() def finish(self): self.daqstream.stop() self.finished.emit() def key_press(self, key): if key == util.key_escape: self.finish() if key == util.key_q: sys.exit() else: super().key_press(key)
def prepare_graphics(self, container): self.canvas = Canvas() container.set_widget(self.canvas) self.init_widgets()
class ValuePrint(Task): def __init__(self, pipeline): """The only thing we need to include in the constructor is the pipeline. """ super(ValuePrint, self).__init__() self.pipeline = pipeline def prepare_design(self, design): """Prepare experimental design. Here is where we define the number of blocks and trials within each block. """ block = design.add_block() block.add_trial(attrs={}) def prepare_graphics(self, container): """Define the GUI by using Items etc. """ self.canvas = Canvas() self.text = Text(text='', color='red') self.canvas.add_item(self.text) container.set_widget(self.canvas) def prepare_daq(self, daqstream): """Initialize input stream and define how many updates (i.e., cycles) take place within each trial (optional). """ self.daqstream = daqstream self.daqstream.start() # The following two lines define how many cycles will take place within # each trial. The length of the trial is n_cycles * (read_size) / rate. # When the counter reaches the maximum count value it will send a # a signal to start the new trial. self.timer = Counter(50) self.timer.timeout.connect(self.finish_trial) def run_trial(self, trial): self.pipeline.clear() self.connect(self.daqstream.updated, self.update) def update(self, data): """Define what happens at each update operation (e.g. ) """ data_proc = self.pipeline.process(data) self.text.qitem.setText("{:4.4f}".format(data_proc)) # The following lines tells the timer that an update has happened # so as to keep track of the cycles and end the program after n_cycles # have happened. self.timer.increment() def finish_trial(self): self.disconnect(self.daqstream.updated, self.update) self.next_trial() def finish(self): self.daqstream.stop() self.finished.emit() def key_press(self, key): if key == util.key_escape: self.finish() else: super().key_press(key)
class Experiment(TransmitterBase): """Experiment workflow manager. Presents the researcher with a prompt for entering session details and then presents the appropriate tasks. Parameters ---------- daq : object, optional A data acquisition device that follows the AxoPy DAQ protocol. See :mod:`axopy.daq`. For mutliple devices, a dictionary, list or tuple is expected. data : str, optional Path to the data. The directory is created for you if it doesn't exist. subject : str, optional The subject ID to use. If not specified, a configuration screen is shown before running the tasks so you can enter it there. This is mostly for experiment writing (to avoid the extra configuration step). allow_overwrite : bool, optional If ``True``, overwrite protection in :class:`Storage` is disabled. This is mostly for experiment writing purposes. """ key_pressed = Transmitter(str) def __init__(self, daq=None, data='data', subject=None, allow_overwrite=False): super(Experiment, self).__init__() self.daq = daq self.storage = Storage(data, allow_overwrite=allow_overwrite) self._receive_keys = False self.subject = subject # main screen self.screen = _MainWindow() # Prepare daqstream(s) self._prepare_daqstream() def configure(self, **options): """Configure the experiment with custom options. This method allows you to specify a number of options that you want to configure with a graphical interface prior to running the tasks. Use keyword arguments to specify which options you want to configure. The options selected/specified in the graphical interface are then returned by this method so that you can alter setup before running the experiment. Each keyword argument should list the data type to configure, such as ``float``, ``str``, or ``int``. You can also provide a list or tuple of available choices for that option. You *do not* need to add an option for the subject name/ID -- that is added automatically if the subject ID was not specified when creating the experiment. """ options['subject'] = str config = _SessionConfig(options).run() self.subject = config['subject'] return config def run(self, *tasks): """Run the experimental tasks.""" if self.subject is None: self.configure() self.screen.key_pressed.connect(self.key_press) # screen to show "Ready" between tasks self.confirm_screen = Canvas(draw_border=False) self.confirm_screen.add_item(Text("Ready (enter to start)")) self.storage.subject_id = self.subject self.tasks = tasks self.current_task = None self.task_iter = iter(self.tasks) self._task_finished() self.screen.run() @property def status(self): return "subject: {} | task: {}".format( self.subject, self.current_task.__class__.__name__) def _run_task(self): self._receive_keys = False # wait for task to finish self.current_task.finished.connect(self._task_finished) # forward key presses to the task self.key_pressed.connect(self.current_task.key_press) self.screen.set_status(self.status) # add a task view con = self.screen.new_container() self.current_task.prepare_graphics(con) self.current_task.prepare_daq(self.daqstream) self.current_task.prepare_storage(self.storage) self.current_task.run() def _task_finished(self): if self.current_task is not None: self.current_task.disconnect_all() self.current_task.finished.disconnect(self._task_finished) self.key_pressed.disconnect(self.current_task.key_press) try: self.current_task = next(self.task_iter) except StopIteration: self.screen.quit() self.screen.set_container(self.confirm_screen) self._receive_keys = True def key_press(self, key): if self._receive_keys: if key == util.key_escape: self.screen.quit() elif key == util.key_return: self._run_task() else: self.key_pressed.emit(key) def _prepare_daqstream(self): if isinstance(self.daq, (list, tuple)): self.daqstream = [] for daq_ in self.daq: self.daqstream.append(DaqStream(daq_)) elif isinstance(self.daq, dict): self.daqstream = dict() for daq_name, daq_ in self.daq.items(): self.daqstream[daq_name] = DaqStream(daq_) else: self.daqstream = DaqStream(self.daq)
def prepare_graphics(self, container): self.countdown = Canvas() self.countdowntext = Text("Flex!") self.countdown.add_item(self.countdowntext) container.set_widget(self.countdown)
class Experiment(TransmitterBase): """Experiment workflow manager. Presents the researcher with a prompt for entering session details and then presents the appropriate tasks. Parameters ---------- daq : object, optional A data acquisition device that follows the AxoPy DAQ protocol. See :mod:`axopy.daq`. data : str, optional Path to the data. The directory is created for you if it doesn't exist. subject : str, optional The subject ID to use. If not specified, a configuration screen is shown before running the tasks so you can enter it there. This is mostly for experiment writing (to avoid the extra configuration step). allow_overwrite : bool, optional If ``True``, overwrite protection in :class:`Storage` is disabled. This is mostly for experiment writing purposes. """ key_pressed = Transmitter(str) def __init__(self, daq=None, data='data', subject=None, allow_overwrite=False): super(Experiment, self).__init__() self.daq = daq self.daqstream = DaqStream(daq) self.storage = Storage(data, allow_overwrite=allow_overwrite) self._receive_keys = False self.subject = subject # main screen self.screen = _MainWindow() def configure(self, **options): """Configure the experiment with custom options. This method allows you to specify a number of options that you want to configure with a graphical interface prior to running the tasks. Use keyword arguments to specify which options you want to configure. The options selected/specified in the graphical interface are then returned by this method so that you can alter setup before running the experiment. Each keyword argument should list the data type to configure, such as ``float``, ``str``, or ``int``. You can also provide a list or tuple of available choices for that option. You *do not* need to add an option for the subject name/ID -- that is added automatically if the subject ID was not specified when creating the experiment. """ options['subject'] = str config = _SessionConfig(options).run() self.subject = config['subject'] return config def run(self, *tasks): """Run the experimental tasks.""" if self.subject is None: self.configure() self.screen.key_pressed.connect(self.key_press) # screen to show "Ready" between tasks self.confirm_screen = Canvas(draw_border=False) self.confirm_screen.add_item(Text("Ready (enter to start)")) self.storage.subject_id = self.subject self.tasks = tasks self.current_task = None self.task_iter = iter(self.tasks) self._task_finished() self.screen.run() @property def status(self): return "subject: {} | task: {}".format( self.subject, self.current_task.__class__.__name__) def _run_task(self): self._receive_keys = False # wait for task to finish self.current_task.finished.connect(self._task_finished) # forward key presses to the task self.key_pressed.connect(self.current_task.key_press) self.screen.set_status(self.status) # add a task view con = self.screen.new_container() self.current_task.prepare_graphics(con) self.current_task.prepare_daq(self.daqstream) self.current_task.prepare_storage(self.storage) self.current_task.run() def _task_finished(self): if self.current_task is not None: self.current_task.disconnect_all() self.current_task.finished.disconnect(self._task_finished) self.key_pressed.disconnect(self.current_task.key_press) try: self.current_task = next(self.task_iter) except StopIteration: self.screen.quit() self.screen.set_container(self.confirm_screen) self._receive_keys = True def key_press(self, key): if self._receive_keys: if key == util.key_escape: self.screen.quit() elif key == util.key_return: self._run_task() else: self.key_pressed.emit(key)