Scripting Scenes

  1. Graphic adapters
    1. Separating stimuli and behavior
    2. Graphic adapters (BoxGraphic, CircleGraphic, PieGraphic, PolygonGraphic, TextGraphic, ImageGraphic, MovieGraphic, SineGrating, RandomDotMotion and GraphicContainer) are special in that they do not have a Success or stop condition. They simply pass the Success or stop status of the child adapter to the parent. (In contrast, other stimulus adapters, such as AudioSound and Stimulator, succeed when the stimulation is completed.) It allows the graphic adapters to be inserted almost anywhere in a chain. See the following codes.

      box = BoxGraphic(eye_); box.List = { [1 1 1], ... [1 0 0], 1, [0 0] }; fix = SingleTarget(box); fix.Target = [0 0]; fix.Threshold = 3; wth = WaitThenHold(fix); wth.WaitTime = 5000; wth.HoldTime = 500; scene = create_scene(wth); run_scene(scene); fix = SingleTarget(eye_); fix.Target = [0 0]; fix.Threshold = 3; box = BoxGraphic(fix); box.List = { [1 1 1], ... [1 0 0], 1, [0 0] }; wth = WaitThenHold(box); wth.WaitTime = 5000; wth.HoldTime = 500; scene = create_scene(wth); run_scene(scene); fix = SingleTarget(eye_); fix.Target = [0 0]; fix.Threshold = 3; wth = WaitThenHold(fix); wth.WaitTime = 5000; wth.HoldTime = 500; box = BoxGraphic(wth); box.List = { [1 1 1], ... [1 0 0], 1, [0 0] }; scene = create_scene(box); run_scene(scene);

      In these three examples, BoxGraphic is inserted in a different part of the chain but they all work. However, inserting graphic adapters in the middle of a chain makes it difficult to reuse the adapters and decreases the code readability. The better practice is to separate the behavior monitoring and the stimulus presentation as below. In that way, the same graphic adapter can be recycled in another chain.

      box = BoxGraphic(null_); % Use NullTracker to free BoxGraphic from behavior tracking box.List = { [1 1 1], [1 0 0], 1, [0 0] }; fix = SingleTarget(eye_); % Only SingleTarget and WaitThenHold are associated with EyeTracker fix.Target = box; % Use the graphic adapter as a target fix.Threshold = 3; wth = WaitThenHold(fix); wth.WaitTime = 5000; wth.HoldTime = 500; scene = create_scene(wth); run_scene(scene);

    3. Controlling multiple graphic objects with one adapter
    4. One graphic adapter can contain multiple objects.

      box = BoxGraphic(null_); box.List = { [1 1 1], [1 0 0], 1, [5 5]; ... % This adapter has 4 squares. [1 1 1], [0 1 0], 1, [-5 5]; ... [1 1 1], [0 0 1], 1, [-5 -5]; ... [1 1 1], [1 1 0], 1, [5 -5]; ... };

      In this case, the length of each adapter property is increased, according to the number of objects, and the property of each object can be manipulated independently.

      >> box.Enable ans = 4×1 logical array 1 1 1 1 >> box.Position ans = 5 5 -5 5 -5 -5 5 -5 >> box.Scale ans = 1 1 1 1 1 1 1 1 >> box.Zorder ans = 0 0 0 0

      >> box.Enable([2 4]) = false; % Hide the 2nd and 4th squares >> box.Scale(3,:) = [2 1]; % Increase the width of the 3rd box twice

      A multi-object adapter can be used to indicate multiple targets.

      box = BoxGraphic(null_); % 4 squares box.List = { [1 1 1], [1 0 0], 1, [5 5]; [1 1 1], [0 1 0], 1, [-5 5]; ... [1 1 1], [0 0 1], 1, [-5 -5]; [1 1 1], [1 1 0], 1, [5 -5] }; mul = MultiTarget(eye_); mul.Target = box; % The same as mul.setTarget(box); mul.Threshold = 3; mul.WaitTime = 5000; mul.HoldTime = 500; scene = create_scene(mul); run_scene(scene);

      All adapters that have the Target property also have the setTarget() method. The optional index argument of setTarget() allows choosing a subset of objects in an adapter.

      mul.setTarget(box,[1 3]); % Use only the 1st and 3rd boxes

      Use GraphicContainer to compose complex graphics from multiple adapters. Note that the add() method of GraphicContainer also has the optional index argument.

      box = BoxGraphic(null_); box.List = { [1 1 1], [1 0 0], 1, [5 5] }; crc = CircleGraphic(null_); crc.List = { [1 1 1], [0 1 0], 1, [-5 5] }; pie = PieGraphic(null_); pie.List = { [1 0 0], [1 1 0], 1, [-5 -5], 45, 270 }; img = ImageGraphic(null_); img.List = { 'A.bmp', [0 0]; 'B.bmp', [5 -5] }; gc = GraphicContainer(box); % Aggregate all gc.add(crc); gc.add(pie); gc.add(img,2); % Add only B.bmp

  2. Adapter aggregators
  3. In the scene framework, adapters are linked as a chain to do complex jobs (for example, acquiring eye positions + checking eye fixation). In addition, multiple chains can be combined into a macro chain with aggregator adapters such as AndAdapter, OrAdapter, AllContinue and AnyContinue. When creating a macro chain, it is even more critical to think through what is the condition that the chain has to meet to finish the scene.

    The code snippet below is an example of a macro chain composed of two child chains: one that checks button press (colored in red) and one that monitors eye positions (in blue). SingleButton and SingleTarget succeed when the button #1 is pressed and the eye is on (-5, 5), respectively, and OrAdapter succeeds when any child chain succeeds. Therefore, the scene ends when either button press or eye fixation is acquired.

    btn = SingleButton(button_); % Child chain 1: ButtonTracker + SingleButton btn.Button = 1; fix = SingleTarget(eye_); % Child chain 2: EyeTracker + SingleTarget fix.Target = [-5 5]; fix.Threshold = 3; or = OrAdapter(btn); % Aggregator: Child chain 1 + Child chain 2 or.add(fix); scene = create_scene(or); run_scene(scene);

    Since the above scene does not have a timer component, it waits for user input indefinitely. We can add WaitThenHold to the second chain, to make the scene finish after a certain period, like the following.

    btn = SingleButton(button_); btn.Button = 1; fix = SingleTarget(eye_); % Child chain 2: EyeTracker + SingleTarget + WaitThenHold fix.Target = [-5 5]; fix.Threshold = 3; wth = WaitThenHold(fix); wth.WaitTime = 3000; % Wait for eye fixation up to 3 s wth.HoldTime = 0; or = OrAdapter(btn); or.add(wth); scene = create_scene(or); run_scene(scene);

    It may look perfect now, but this scene will not end even if there is no user input for 3 s. It is because WaitThenHold may stop with or without a success (i.e., with or without eye fixation) but stopping without a success does not satisfy OrAdapter.

    To make the scene work as we intended, we need to use a different aggregator that watches the stop states of child chains, instead of the success states.

    btn = SingleButton(button_); btn.Button = 1; fix = SingleTarget(eye_); fix.Target = [-5 5]; fix.Threshold = 3; wth = WaitThenHold(fix); wth.WaitTime = 3000; wth.HoldTime = 0; ac = AllContinue(btn); % New aggregator ac.add(wth); scene = create_scene(ac); run_scene(scene);

    AllContinue stops when any of its child chains stops, regardless of their success states. Therefore the scene will end whether WaitThenHold is finished by eye fixation or by time out. AndAdapter and OrAdapter monitor the success states of their child chains; AllContinue and AnyContinue, the stop states.

    As shown in these examples, it should be considered carefully whether to use the success state or the stop state to finish a scene when designing a complex macro chain. The success and stop conditions of each adapter are explained in the timing script function manual. Also check out other special aggregators, such as Concurrent and Sequential, in the manual.

The National Institute of Mental Health (NIMH) is part of the National Institutes of Health (NIH), a component of the U.S. Department of Health and Human Services.