Millisecond Forums

creating fixed picture locations for different trial types

https://forums.millisecond.com/Topic17191.aspx

By charlottebooth - 9/22/2015

I am creating a visual search task with two different trial types - "old" and "new" ones:
"old" trials need to create 12 fixed search displays - with 11 distractors and 1 target picture, which will be repeated in every one of 16 blocks.
"new" trials need to create semi-random search displays - the distractors need to be in random locations, but the target needs to be in 12 fixed locations that are different to the 12 fixed locations of the "old" trials.
This task has 48 possible positions for the pictures (8x6 invisible grid).
How can I do this so that it creates random "old"/"new" configurations for each new participant?

I have attached my script so far.
By Dave - 9/22/2015

Conceptually, what you need to do is this:

(1) At the beginning of the experiment (/onexptbegin), select 12 positions of your 48 positions at random for your "target" in "old" trials. Store those 12 positions in a dedicated list or counter. Do the same for 12 positions of the "target" in "new" configurations.

(2) For the "old" trials, you'll also want to assemble lists for the distractor positions /onexptbegin. Pick one of the "old" target positions you selected under one, pick positions for the 11 distractors, store the overall result (i.e., the entire configuration) in dedicated lists. Repeat for all 12 "old" target positions selected under (1).

(3) At runtime, your <old> trials ought to sample one of the 12 "old" configurations generated under (2). For "new" trials, it should suffice to simply sample one of the "new" target positions gathered under (1) and place the 11 distractors randomly into the remaining 47 positions at runtime (you already know how to do this).
By charlottebooth - 9/23/2015

Cool! So would I need to create completely new lists or counters? Or would I be editing my pre-existing ones?

And what would the syntax roughly look like for :
<expt CC>
/onexptbegin = [               ???           ]
By Dave - 9/23/2015

You would have one or several initial lists that hold e.g. your coordinates (x/y pairs) for the target / distractors. You'd have several initially empty lists in your script. You would then populate those lists at the beginning of the experiment. See e.g. https://www.millisecond.com/forums/FindPost15181.aspx for an introductory example re. how to construct such lists. Then see https://www.millisecond.com/forums/FindPost15870.aspx later in the thread for an extension.
By charlottebooth - 9/23/2015

So for (1) it would maybe be something like:

<list oldtargets>
</list>

<list oldtargetcoord>
/poolsize = 12
/selectionrate = always
/items = (values.targetx, values.targety)
</list>

<expt example>
/onexptbegin = [list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex); list.oldtargets.appenditem(list.oldtargetcoord.nextindex) ]
</expt>


By charlottebooth - 9/23/2015

But I cant imagine whether the previous work in trial is obsolete?:
/ ontrialbegin = [values.targetpos=counter.targetspositions.selectedvalue; values.targetx=counter.targetsxpos.selectedvalue; values.targety=counter.targetsypos.selectedvalue;
values.targetx+=values.jitterstep*counter.randomjitter.selectedvalue; values.targety+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor1pos=counter.distractorpositions.selectedvalue; values.distractor1x=counter.distractorxpos.selectedvalue; values.distractor1y=counter.distractorypos.selectedvalue;
values.distractor1x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor1y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor2pos=counter.distractorpositions.selectedvalue; values.distractor2x=counter.distractorxpos.selectedvalue; values.distractor2y=counter.distractorypos.selectedvalue;
values.distractor2x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor2y+=values.jitterstep*counter.randomjitter.selectedvalue;            
                  values.distractor3pos=counter.distractorpositions.selectedvalue; values.distractor3x=counter.distractorxpos.selectedvalue; values.distractor3y=counter.distractorypos.selectedvalue;
values.distractor3x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor3y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor4pos=counter.distractorpositions.selectedvalue; values.distractor4x=counter.distractorxpos.selectedvalue; values.distractor4y=counter.distractorypos.selectedvalue;
values.distractor4x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor4y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor5pos=counter.distractorpositions.selectedvalue; values.distractor5x=counter.distractorxpos.selectedvalue; values.distractor5y=counter.distractorypos.selectedvalue;
values.distractor5x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor5y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor6pos=counter.distractorpositions.selectedvalue; values.distractor6x=counter.distractorxpos.selectedvalue; values.distractor6y=counter.distractorypos.selectedvalue;
values.distractor6x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor6y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor7pos=counter.distractorpositions.selectedvalue; values.distractor7x=counter.distractorxpos.selectedvalue; values.distractor7y=counter.distractorypos.selectedvalue;
values.distractor7x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor7y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor8pos=counter.distractorpositions.selectedvalue; values.distractor8x=counter.distractorxpos.selectedvalue; values.distractor8y=counter.distractorypos.selectedvalue;
values.distractor8x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor8y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor9pos=counter.distractorpositions.selectedvalue; values.distractor9x=counter.distractorxpos.selectedvalue; values.distractor9y=counter.distractorypos.selectedvalue;
values.distractor9x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor9y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor10pos=counter.distractorpositions.selectedvalue; values.distractor10x=counter.distractorxpos.selectedvalue; values.distractor10y=counter.distractorypos.selectedvalue;
values.distractor10x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor10y+=values.jitterstep*counter.randomjitter.selectedvalue;
                  values.distractor11pos=counter.distractorpositions.selectedvalue; values.distractor11x=counter.distractorxpos.selectedvalue; values.distractor11y=counter.distractorypos.selectedvalue;
values.distractor11x+=values.jitterstep*counter.randomjitter.selectedvalue; values.distractor11y+=values.jitterstep*counter.randomjitter.selectedvalue]
By Dave - 9/23/2015

The previous work in the <trial> is *not* obsolete.

At the beginning of the experiment you'll want to to construct, "fill" or assemble the lists that the respective <trial> elements then *later during* the experiment sample from.

The 12 target posititions you'll be using for the "new" trials, for example, are *not known* beforehand. Hence you cannot just hardcode 12 specific positions in a list somewhere.

Instead, you need to 1st randomly *select* those 12 positions from the total of 48 positions and store those in a list. That list then is where your "new" trials sample their target positions from.

Hope this clarifies.

One further tip: Before you start thinking about writing any code, try to imagine how you would do things in the real world with physical objects. Imagine your grid / set of 48 positions as a deck of 48 cards. Then proceed to draw 12 random cards and put them in a deck labeled "target new", etc. I find that thinking about matters of random selection in this way helps.
By charlottebooth - 9/24/2015

Sorry I have some more questions :blink:


<block myblock>
/ onblockbegin = [list.sourceitems.appenditem(list.allitems.nextindex); list.sourceitems.appenditem(list.allitems.nextindex);
    list.sourceitems.appenditem(list.allitems.nextindex); list.sourceitems.appenditem(list.allitems.nextindex);
    list.targetitems.appenditem(list.allitems.nextindex); list.targetitems.appenditem(list.allitems.nextindex);]
/ trials = [1-4=showsources; 5-6=showtargets]
</block>

What does appenditem - and nextindex do/mean?

<trial showsources>
/ stimulusframes = [1=sourcetxt]
/ validresponse = (57)
</trial>

<trial showtargets>
/ stimulusframes = [1=targettxt]
/ validresponse = (57)
</trial>

<text sourcetxt>
/items = myitems
/ select = list.sourceitems.nextvalue
/ txcolor = blue
</text>

<text targettxt>
/items = myitems
/ select = list.targetitems.nextvalue
/ txcolor = red
</text>

<item myitems>
/ 1 = "A"
/ 2 = "B"
/ 3 = "C"
/ 4 = "D"
/ 5 = "E"
/ 6 = "F"
</item>
*Will I need to make 48 of these for all the possible coordinates? and what would that looks like? (ie "list.targetx=counter.target")?

<list allitems>
/ poolsize = 6
/ selectionrate = always
</list>
*Would the pool size here be 12 (for stimuli) or 48 for positions?

<list sourceitems>
</list>

<list targetitems>
</list>

*would I need 3 empty lists for oldtargets, newtargets, distractorpositions?
By Dave - 9/24/2015

#1: The appenditem() function appends an item to the specified list. So, if the list is empty in the begining, the 1st time you apply that function, the respective item will be the 1st in the formerly empty list. The next time you apply it, it adds another item (then 2nd) and so forth. The items that are added come from list.allitems in the example. A random index number (nextindex; here between 1 and 6) is sampled from list.allitems and added to list.sourceitmes. That's what

list.sourceitems.appenditem(list.allitems.nextindex)

does in the example. For details on list properties and functions, see the language reference entry for the <list> element in the documentation.

#2: Yes, you need to work with more items, of course. You have 48 positions. As per previous examples, you can simply number them 1 to 48. You want to select 12 of those 48 at random and add them to one list (= target positions to be used in "new" trials), and another 12 at random to another list (=target positions to be used in "old" trials). How that works -- sampling from a "master" list at random, and adding the sampled items to (a) different list(s) -- is what the example covers.

#3: As per #2, the /poolsize would be 48.

#4: Yes, you need several lists. Exactly how many is a matter of various design decisions. Again, as per #2, you definitely need
- one list for "old" target positions (12 items will end up in that list),
- one list for "new" target positions (another 12 items will end up there),
- one or several lists that store the set of distractor positions associated with a given target position in "old" trials.

Leave aside the "old" trials for now. Start with setting up the "new" trials. I.e., from the list that holds your total set of 48 positions, select 12 at random / add them to a list. Sample target positions from that list in "new" trials, while distributing the distractors randomly as per previous examples.

By charlottebooth - 9/24/2015

Ok so my first immediate problem is how the list can hold all the positions.

<list newtargets>
</list>

<list allpositions>
/poolsize = 46
/selectionrate = always
</list>

<item positions>
/1= how to specify a position here which is horizontally 29% and vertically 34% for example
/2= and then this one would be 29% horizontally and 40.5% vertically
/3=
/4=

</item>



By Dave - 9/24/2015

#1: You don't need any <item> element. Forget about that.
#2: The poolsize is wrong.

The list doesn't need to "hold all positions". All it needs to hold is something that *identifies* a given position uniquely -- i.e., a number between 1 and 48 (inclusive).

Look back at https://www.millisecond.com/forums/FindPost17196.aspx and notice that we've abstracted positions to numerical identifiers (1 to 4) in the example.

For now focus *solely* on sampling 12 random numbers from one list and storing them in another.
By charlottebooth - 9/24/2015

Thanks! So is this in any way correct:

<picture targets>
/items = targets
/select = list.newtargets.nextvalue
/vposition = values.targety
/hposition = values.targetx
/size = (3%, 3%)
</picture>

<list newtargets>
</list>

<list targetpositions>
/poolsize = 48
/selectionrate = always
</list>


<expt CC>
/blocks = [1=experimental]
/onexptbegin = [list.newtargets.appenditem(list.targetpositions.nextindex);
                         list.newtargets.appenditem(list.targetpositions.nextindex); 
                        list.newtargets.appenditem(list.targetpositions.nextindex);
                        list.newtargets.appenditem(list.targetpositions.nextindex); ..... etc. x12
</expt>


By Dave - 9/24/2015

<expt CC>
/blocks = [1=experimental]
/onexptbegin = [list.newtargets.appenditem(list.targetpositions.nextindex);
                         list.newtargets.appenditem(list.targetpositions.nextindex); 
                        list.newtargets.appenditem(list.targetpositions.nextindex);
                        list.newtargets.appenditem(list.targetpositions.nextindex); ..... etc. x12
</expt>

The above is correct. But

<picture targets>
/items = targets
/select = list.newtargets.nextvalue
/vposition = values.targety
/hposition = values.targetx
/size = (3%, 3%)
</picture>

is *not* what you want. You don't want the target *item* selected according to what's in the newtargets list. You want the *position* selected. I.e., in the "new" <trial>, sample a value from list.newtargets. Store it in a <values> entry. Set values.targetx and values.targety to the coordinates *corresponding* to the numerical position indicator you sampled from list.newtargets.
By Dave - 9/26/2015

This example summarizes where we are and puts the various pieces so far together.

<values>
/ targetpos = 0
/ targetx = 0
/ targety = 0

/ d1pos = 0
/ d1x = 0
/ d1y = 0

/ d2pos = 0
/ d2x = 0
/ d2y = 0

/ d3pos = 0
/ d3x = 0
/ d3y = 0

/ d4pos = 0
/ d4x = 0
/ d4y = 0

/ d5pos = 0
/ d5x = 0
/ d5y = 0

/ d6pos = 0
/ d6x = 0
/ d6y = 0

/ d7pos = 0
/ d7x = 0
/ d7y = 0

/ d8pos = 0
/ d8x = 0
/ d8y = 0

/ d9pos = 0
/ d9x = 0
/ d9y = 0

/ d10pos = 0
/ d10x = 0
/ d10y = 0

/ d11pos = 0
/ d11x = 0
/ d11y = 0

/ jitterstep = 1%
</values>

<expt>
/ onexptbegin = [list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
    list.targetpositionsnew.appenditem(list.allpositions.nextindex);
]
/ blocks = [1-4 = taskblock]
</expt>

<page blockstartpage>
^start of new block
</page>


<block taskblock>
/ preinstructions = (blockstartpage)
/ trials = [1-12=newtrial]
</block>

<trial newtrial>
/ ontrialbegin = [list.distractorpositionsnew.reset(); text.target.textcolor=red; ]
/ ontrialbegin = [values.targetpos=list.targetpositionsnew.nextvalue;
    values.targetx=list.x.item(values.targetpos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.targety=list.y.item(values.targetpos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d1pos=list.distractorpositionsnew.nextvalue;
    values.d1x=list.x.item(values.d1pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d1y=list.y.item(values.d1pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d2pos=list.distractorpositionsnew.nextvalue;
    values.d2x=list.x.item(values.d2pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d2y=list.y.item(values.d2pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d3pos=list.distractorpositionsnew.nextvalue;
    values.d3x=list.x.item(values.d3pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d3y=list.y.item(values.d3pos)+(values.jitterstep*list.randomjitter.nextvalue);
   
    values.d4pos=list.distractorpositionsnew.nextvalue;
    values.d4x=list.x.item(values.d4pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d4y=list.y.item(values.d4pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d5pos=list.distractorpositionsnew.nextvalue;
    values.d5x=list.x.item(values.d5pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d5y=list.y.item(values.d5pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d6pos=list.distractorpositionsnew.nextvalue;
    values.d6x=list.x.item(values.d6pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d6y=list.y.item(values.d6pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d7pos=list.distractorpositionsnew.nextvalue;
    values.d7x=list.x.item(values.d7pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d7y=list.y.item(values.d7pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d8pos=list.distractorpositionsnew.nextvalue;
    values.d8x=list.x.item(values.d8pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d8y=list.y.item(values.d8pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d9pos=list.distractorpositionsnew.nextvalue;
    values.d9x=list.x.item(values.d9pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d9y=list.y.item(values.d9pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d10pos=list.distractorpositionsnew.nextvalue;
    values.d10x=list.x.item(values.d10pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d10y=list.y.item(values.d10pos)+(values.jitterstep*list.randomjitter.nextvalue);

    values.d11pos=list.distractorpositionsnew.nextvalue;
    values.d11x=list.x.item(values.d11pos)+(values.jitterstep*list.randomjitter.nextvalue);
    values.d11y=list.y.item(values.d11pos)+(values.jitterstep*list.randomjitter.nextvalue);
    ]
/ pretrialpause = 500
/ stimulusframes =  [1=target,d1,d2,d3,d4,d5,d6,d7,d8,d9,d10,d11]
/ validresponse = (57)
</trial>

<text target>
/ items = ("T1", "T2")
/ hposition = values.targetx
/ vposition = values.targety
</text>

<text d1>
/ items = distractoritems
/ hposition = values.d1x
/ vposition = values.d1y
</text>

<text d2>
/ items = distractoritems
/ hposition = values.d2x
/ vposition = values.d2y
</text>

<text d3>
/ items = distractoritems
/ hposition = values.d3x
/ vposition = values.d3y
</text>

<text d4>
/ items = distractoritems
/ hposition = values.d4x
/ vposition = values.d4y
</text>

<text d5>
/ items = distractoritems
/ hposition = values.d5x
/ vposition = values.d5y
</text>

<text d6>
/ items = distractoritems
/ hposition = values.d6x
/ vposition = values.d6y
</text>

<text d7>
/ items = distractoritems
/ hposition = values.d7x
/ vposition = values.d7y
</text>

<text d8>
/ items = distractoritems
/ hposition = values.d8x
/ vposition = values.d8y
</text>

<text d9>
/ items = distractoritems
/ hposition = values.d9x
/ vposition = values.d9y
</text>

<text d10>
/ items = distractoritems
/ hposition = values.d10x
/ vposition = values.d10y
</text>

<text d11>
/ items = distractoritems
/ hposition = values.d11x
/ vposition = values.d11y
</text>

<item distractoritems>
/ 1 = "L1"
/ 2 = "L2"
/ 3 = "L3"
/ 4 = "L4"
</item>


<list allpositions>
/ poolsize = 48
/ selectionrate = always
</list>

<list targetpositionsnew>
</list>

<list distractorpositionsnew>
/ items = (1,2,3,4,5,6,7,8,
    9,10,11,12,13,14,15,16,
    17,18,19,20,21,22,23,24,
    25,26,27,28,29,30,31,32,
    33,34,35,36,37,38,39,40,
    41,42,43,44,45,46,47,48)
/ not = (values.targetpos)
/ selectionrate = always
</list>

<list randomjitter>
/ items = (-3,-2,-1, 1, 2, 3)
/ selectionrate = always
/ selectionmode = random
/ replace = true
</list>

<list x>
/ items = (6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%,
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%,
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%,
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%,
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%,
    6.25%, 18.75%, 31.25%, 43.75%, 56.25%, 68.75%, 81.25%, 93.75%)
</list>

<list y>
/ items = (8.33%, 8.33%, 8.33%, 8.33%, 8.33%, 8.33%, 8.33%, 8.33%,
    25.00%, 25.00%, 25.00%, 25.00%, 25.00%, 25.00%, 25.00%, 25.00%,
    41.67%, 41.67%, 41.67%, 41.67%, 41.67%, 41.67%, 41.67%, 41.67%,
    58.33%, 58.33%, 58.33%, 58.33%, 58.33%, 58.33%, 58.33%, 58.33%,
    75.00%, 75.00%, 75.00%, 75.00%, 75.00%, 75.00%, 75.00%, 75.00%,
    91.67%, 91.67%, 91.67%, 91.67%, 91.67%, 91.67%, 91.67%, 91.67%)
</list>

Please work through that and make sure you understand every part of it. If there's something you don't understand, please don't hesitate to ask about those specific portions of the code. A good exercise would be to comment the code, i.e., write up short explanations of what each part does.

Then start thinking about how to tackle the "old" trials. I.e., what additional steps have to be taken to assemble those configurations.

Hope this helps.