예제 #1
0
class Test_textbox(object):
    def setup_class(self):
        self.win = Window([128, 128],
                          pos=[50, 50],
                          allowGUI=False,
                          autoLog=False)

    def teardown_class(self):
        self.win.close()

    def test_basic(self):
        for units in ['norm', 'pix']:
            self.win.units = units
            tb = TextBox(self.win, size=(1, .5), pos=(0, -.25))
            tb.setBackgroundColor('white')
            text = 'abc DEF'
            self.win.flip()
            tb.setText(text)
            tb.draw()
            self.win.flip()
            assert tb.getText() == tb.getDisplayedText() == text

    def test_something(self):
        # to-do: test visual display, char position, etc
        pass
예제 #2
0
    def play_sound(self, window: visual.Window):
        """
        Uniformly choses a frequency to play according to the number of repetitions for each one and plays it.
        :param window:
        :return:
        """
        total_repetitions = sum(self._repetitions)
        if total_repetitions == 0:
            self._repetitions = self._original_reps
            total_repetitions = sum(self._repetitions)

        probs = [float(rep) / total_repetitions for rep in self._repetitions]
        sound_index = np.random.choice(range(len(self._freqs)), p=probs)
        window.flip()
        new_sound = sound.Sound(self._freqs[sound_index], secs=self._duration)

        data_logger.record_data(
            ['Play sound', main_clock.getTime()], ParallelData.SOUND_START)

        new_sound.play()
        data_logger.record_data(
            ['Sound end', main_clock.getTime()], ParallelData.SOUND_START)

        window.flip()
        self._repetitions[sound_index] -= 1
예제 #3
0
파일: session.py 프로젝트: cdwijs/exptools2
 def _create_window(self):
     """ Creates a window based on the settings and calculates framerate. """
     win = Window(monitor=self.monitor.name, **self.settings['window'])
     win.flip(clearBuffer=True)
     self.actual_framerate = win.getActualFrameRate()
     t_per_frame = 1. / self.actual_framerate
     logging.warn(f"Actual framerate: {self.actual_framerate:.5f} "
                  f"(1 frame = {t_per_frame:.5f})")
     return win
예제 #4
0
def fixate(window: visual.Window, text: str = None):
    visual.TextStim(
        win=window,
        text=text,
        pos=[0, 5],
    ).draw()
    visual.GratingStim(win=window, size=0.2, sf=0).draw()

    window.flip()
    event.waitKeys(keyList="space", maxWait=5)
예제 #5
0
 def _create_window(self):
     """ Creates a window based on the settings and calculates framerate. """
     win = Window(monitor=self.monitor.name, **self.settings['window'])
     win.flip(clearBuffer=True)
     self.actual_framerate = win.getActualFrameRate()
     if self.actual_framerate is None:
         logging.warn("framerate not measured, substituting 60 by default")
         self.actual_framerate = 60.0
     t_per_frame = 1. / self.actual_framerate
     logging.warn(f"Actual framerate: {self.actual_framerate:.5f} "
                  f"(1 frame = {t_per_frame:.5f})")
     return win
예제 #6
0
class Test_class_ProjectorFramePacker(object):
    """
    """
    def setup_class(self):
        self.win = Window(monitor='LightCrafter4500', screen=2, fullscr=True, color='gray', useFBO = True)
        self.win.setRecordFrameIntervals()
        self.packer = ProjectorFramePacker (self.win)

    def teardown_class(self):
        self.win.close()

    def flip (self, frames=120):
        for i in range(frames):
            self.win.flip()
예제 #7
0
파일: task.py 프로젝트: theGreenJedi/BciPy
def print_message(window: visual.Window, message: str = "Initializing..."):
    """Draws a message on the display window using default config.

    Parameters
    ----------
        window (object): Psychopy Window Object, should be the same as the one
            used in the experiment
        parameters (dict): Dictionary of session parameters

    Returns
    -------
        TextStim object
    """
    message_stim = visual.TextStim(win=window, text=message)
    message_stim.draw()
    window.flip()
    return message_stim
예제 #8
0
class Test_textbox(object):
    def setup_class(self):
        self.win = Window([128,128], pos=[50,50], allowGUI=False, autoLog=False)

    def teardown_class(self):
        self.win.close()

    def test_basic(self):
        for units in ['norm', 'pix']:
            self.win.units = units
            tb = TextBox(self.win, size=(1,.5), pos=(0,-.25))
            tb.setBackgroundColor('white')
            text = 'abc DEF'
            self.win.flip()
            tb.setText(text)
            tb.draw()
            self.win.flip()
            assert tb.getText() == tb.getDisplayedText() == text

    def test_something(self):
        # to-do: test visual display, char position, etc
        pass
예제 #9
0
def main():
    groups = create_stim_sequence(BLOCK1, BLOCK2, BLOCK3, TRIALREPEATS)
    print groups

    disp = Window(size=SIZE,
                  monitor=MON,
                  units='deg',
                  color=BACKCOL,
                  screen=1,
                  fullscr=True)

    mouse = Mouse()

    fixmark = Circle(disp, radius=0.05, edges=32, pos=CENTER, lineColor=FIXCOL)

    images = []

    for item in CIRCLES.keys():
        image = ImageStim(disp,
                          image=CIRCLES[item][1],
                          pos=CIRCLES[item][0],
                          size=CIRCLES[item][3])
        images.append(image)

    fixmark.draw()
    draw_group(images)
    disp.flip()

    while True:
        button = mouse.getPressed()
        if button[0]:
            break

    for item in groups:
        flashes = []
        for i in item:
            flash = ImageStim(disp,
                              image=CIRCLES[i][2],
                              pos=CIRCLES[i][0],
                              size=CIRCLES[i][3])
            flashes.append(flash)
        fixmark.draw()
        draw_group(images)
        draw_group(flashes)
        disp.flip()
        wait(FLASH)
        fixmark.draw()
        draw_group(images)
        wait(PAUSE)
        disp.flip()

    disp.close()
예제 #10
0
class Test_textbox(_TestColorMixin, _TestUnitsMixin):
    def setup(self):
        self.win = Window((128, 128),
                          pos=(50, 50),
                          monitor="testMonitor",
                          allowGUI=False,
                          autoLog=False)
        self.error = _BaseErrorHandler()
        self.textbox = TextBox2(
            self.win,
            "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
            "Noto Sans",
            alignment="top left",
            lineSpacing=1,
            pos=(0, 0),
            size=(1, 1),
            units='height',
            letterHeight=0.1,
            colorSpace="rgb")
        self.obj = self.textbox  # point to textbox for mixin tests
        # Pixel which is the border color
        self.borderPoint = (0, 0)
        self.borderUsed = True
        # Pixel which is the fill color
        self.fillPoint = (2, 2)
        self.fillUsed = True
        # Textbox foreground is too unreliable due to fonts for pixel analysis
        self.foreUsed = False

    def teardown(self):
        self.win.close()

    def test_glyph_rendering(self):
        # Prepare textbox
        self.textbox.colorSpace = 'rgb'
        self.textbox.color = 'white'
        self.textbox.fillColor = (0, 0, 0)
        self.textbox.borderColor = None
        self.textbox.opacity = 1

        # Add all Noto Sans fonts to cover widest possible base of handles characters
        for font in [
                "Noto Sans", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR",
                "Noto Sans SC", "Noto Sans TC", "Niramit", "Indie Flower"
        ]:
            self.textbox.fontMGR.addGoogleFont(font)
        # Some exemplar text to test basic TextBox rendering
        exemplars = [
            # An English pangram
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Noto Sans",
                "size": 16,
                "screenshot": "exemplar_1.png"
            },
            # The same pangram in IPA
            {
                "text":
                "ə saɪkəʊpaɪ zɛlət nəʊz ə smidge ɒv wx, bʌt ˈʤɑːvəskrɪpt ɪz ðə ˈkwɛsʧən",
                "font": "Noto Sans",
                "size": 16,
                "screenshot": "exemplar_2.png"
            },
            # The same pangram in Hangul
            {
                "text": "아 프시초피 제알롣 크노W스 아 s믿게 오f wx, 붇 자v앗c립t 잇 테 q왯디온",
                "font": "Noto Sans KR",
                "size": 16,
                "screenshot": "exemplar_3.png"
            },
            # A noticeably non-standard font
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Indie Flower",
                "size": 16,
                "screenshot": "exemplar_4.png",
            }
        ]
        # Some text which is likely to cause problems if something isn't working
        tykes = [
            # Text which doesn't render properly on Mac (Issue #3203)
            {
                "text": "कोशिकायें",
                "font": "Noto Sans",
                "size": 16,
                "screenshot": "tyke_1.png"
            },
            # Thai text which old Text component couldn't handle due to Pyglet
            {
                "text": "ขาว แดง เขียว เหลือง ชมพู ม่วง เทา",
                "font": "Niramit",
                "size": 16,
                "screenshot": "tyke_2.png"
            },
            # Text which had the top cut off
            {
                "text": "โฬิปื้ด็ลู",
                "font": "Niramit",
                "size": 36,
                "screenshot": "cutoff_top.png"
            },
        ]
        # Test each case and compare against screenshot
        for case in exemplars + tykes:
            self.textbox.reset()
            self.textbox.fontMGR.addGoogleFont(case['font'])
            self.textbox.letterHeight = layout.Size(case['size'], "pix",
                                                    self.win)
            self.textbox.font = case['font']
            self.textbox.text = case['text']
            self.win.flip()
            self.textbox.draw()
            if case['screenshot']:
                # Uncomment to save current configuration as desired
                filename = "textbox_{}_{}".format(self.textbox._lineBreaking,
                                                  case['screenshot'])
                #self.win.getMovieFrame(buffer='back').save(Path(utils.TESTS_DATA_PATH) / filename)
                utils.compareScreenshot(Path(utils.TESTS_DATA_PATH) / filename,
                                        self.win,
                                        crit=20)

    def test_colors(self):
        # Do base tests
        _TestColorMixin.test_colors(self)
        # Do own custom tests
        self.textbox.text = "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question."
        # Some exemplar text to test basic colors
        exemplars = [
            # White on black in rgb
            {
                "color": (1, 1, 1),
                "fillColor": (-1, -1, -1),
                "borderColor": (-1, -1, -1),
                "space": "rgb",
                "screenshot": "colors_WOB.png"
            },
            # White on black in named
            {
                "color": "white",
                "fillColor": "black",
                "borderColor": "black",
                "space": "rgb",
                "screenshot": "colors_WOB.png"
            },
            # White on black in hex
            {
                "color": "#ffffff",
                "fillColor": "#000000",
                "borderColor": "#000000",
                "space": "hex",
                "screenshot": "colors_WOB.png"
            },
            {
                "color": "red",
                "fillColor": "yellow",
                "borderColor": "blue",
                "space": "rgb",
                "screenshot": "colors_exemplar1.png"
            },
            {
                "color": "yellow",
                "fillColor": "blue",
                "borderColor": "red",
                "space": "rgb",
                "screenshot": "colors_exemplar2.png"
            },
            {
                "color": "blue",
                "fillColor": "red",
                "borderColor": "yellow",
                "space": "rgb",
                "screenshot": "colors_exemplar3.png"
            },
        ]
        # Some colors which are likely to cause problems if something isn't working
        tykes = [
            # Text only
            {
                "color": "white",
                "fillColor": None,
                "borderColor": None,
                "space": "rgb",
                "screenshot": "colors_tyke1.png"
            },
            # Fill only
            {
                "color": None,
                "fillColor": "white",
                "borderColor": None,
                "space": "rgb",
                "screenshot": "colors_tyke2.png"
            },
            # Border only
            {
                "color": None,
                "fillColor": None,
                "borderColor": "white",
                "space": "rgb",
                "screenshot": "colors_tyke3.png"
            },
        ]
        # Test each case and compare against screenshot
        for case in exemplars + tykes:
            # Raise error if case spec does not contain all necessary keys
            if not all(
                    key in case for key in
                ["color", "fillColor", "borderColor", "space", "screenshot"]):
                raise KeyError(
                    f"Case spec for test_colors in class {self.__class__.__name__} ({__file__}) invalid, test cannot be run."
                )
            # Apply params from case spec
            self.textbox.colorSpace = case['space']
            self.textbox.color = case['color']
            self.textbox.fillColor = case['fillColor']
            self.textbox.borderColor = case['borderColor']
            for lineBreaking in ('default', 'uax14'):
                self.win.flip()
                self.textbox.draw()
            if case['screenshot']:
                # Uncomment to save current configuration as desired
                filename = "textbox_{}_{}".format(self.textbox._lineBreaking,
                                                  case['screenshot'])
                # self.win.getMovieFrame(buffer='back').save(Path(utils.TESTS_DATA_PATH) / filename)
                utils.compareScreenshot(Path(utils.TESTS_DATA_PATH) / filename,
                                        self.win,
                                        crit=20)
예제 #11
0
파일: mdts.py 프로젝트: yassalab/MDT-Suite
class MDTS(object):
    def __init__(self, logfile, imgDir, screenType, trialDuration, ISI,
                 trialsPer, selfPaced, practiceTrials, inputButtons,
                 pauseButton):

        self.logfile = logfile
        self.trialDuration = trialDuration
        self.selfPaced = selfPaced
        self.ISI = ISI
        self.trialsPer = trialsPer
        self.numTrials = (self.trialsPer * 4)  #Trials/phase = 4x trials/cond
        self.imgDir = imgDir
        self.imgIdx = 0
        self.runPracticeTrials = practiceTrials
        self.leftButton = inputButtons[0]
        self.rightButton = inputButtons[1]
        self.pauseButton = pauseButton

        if (screenType == 'Windowed'):
            screenSelect = False
        elif (screenType == 'Fullscreen'):
            screenSelect = True
        self.window = Window(fullscr=screenSelect,
                             units='pix',
                             color='White',
                             allowGUI=False)
        self.imageWidth = self.window.size[1] / 6

        #Window must be set up before imgs, as img position based on window size
        self.imageList = self.SegmentImages()
        self.clock = Clock()

        #Initialize scorelist for 4 categories;; [correct,inc,resp]
        self.scoreList = []
        for i in range(0, 4):
            self.scoreList.append([0, 0, 0])

    def Pause(self):
        """Pauses the task, and displays a message waiting for a spacebar
        input from the user before continuing to proceed.
        """
        pauseMsg = "Experiment Paused\n\nPress '{}' to continue".format(
            self.pauseButton)
        pauseText = TextStim(self.window,
                             text=pauseMsg,
                             color='Black',
                             height=40)
        pauseText.draw(self.window)
        self.window.flip()
        waitKeys(keyList=[self.pauseButton])
        clearEvents()

    def CreatePosPair(self, moveType):
        """Generates two (x,y) coordinates to be associated with a particular
        image - the first being the study phase position, and second being the
        test phase position, which is a translation in any direction by 4
        degrees of distances - none, small, big, corner.

        moveType: the amount of relative distance across the screen to move
            -0: Non move (xA,yA) = (xB,yB)
            -1: Lure High: Max Distance / 3
            -2: Lure Low: (Max Distance*2) / 3
            -3: Opposite Corners: Max Distance
        return: a tuple of two coordinate pairs ((xA,yA),(xB,yB))
                (start position of img, end position of img) 
        """

        #Map a bottom left oriented coordinate system to a center oriented one
        def CoordMap(x, y):
            xM = int(x - winL / 2)
            yM = int(y - winH / 2)
            return (xM, yM)

        #Checks whether (x,y) coordinate is near corner
        def IsNearCorner(xTest, yTest):
            if ((xTest <= (x1 + imgDis) and yTest <= (y1 + imgDis))
                    or (xTest <= (x1 + imgDis) and yTest >= (y2 - imgDis))
                    or (xTest >= (x2 - imgDis) and yTest <=
                        (y1 + imgDis)) or (xTest >= (x2 - imgDis) and yTest >=
                                           (y2 - imgDis))):
                return True
            else:
                return False

        #Generates a random point on a circle about (xA,yA) with a given radius
        def GenCoordMove(xA, yA, radius):
            deg = random.randint(0, 359)
            rad = math.radians(deg)
            vecX = math.cos(rad)
            vecY = math.sin(rad)
            xR = int(radius * vecX)
            yR = int(radius * vecY)
            xB = xA + xR
            yB = yA + yR
            return (xB, yB)

        #Standard distance formula - use for diagnostics
        def Dist(x1, y1, x2, y2):
            return (math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2)))

        #Calculate the length, in pixels, of the small/large moves
        winL = self.window.size[0]
        winH = self.window.size[1]
        midDis = self.imageWidth / 2
        imgDis = self.imageWidth
        x2 = math.ceil(winL - midDis)
        x1 = math.floor(0 + midDis)
        y2 = math.ceil(winH - midDis)
        y1 = math.floor(0 + midDis)
        maxDis = math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2))
        distSmall = math.floor(maxDis / 4)
        distLarge = math.floor((maxDis * 2) / 4)

        #Opposite corner condition: randomly choose 1 of 4 corner moves
        if (moveType == 3):
            corner = random.randint(0, 3)
            if (corner == 0): return (CoordMap(x2, y2), CoordMap(x1, y1))
            elif (corner == 1): return (CoordMap(x1, y2), CoordMap(x2, y1))
            elif (corner == 2): return (CoordMap(x1, y1), CoordMap(x2, y2))
            elif (corner == 3): return (CoordMap(x2, y1), CoordMap(x1, y2))

        #If not corner, generate random starting position and create
        #ending position based on
        else:
            while (1):
                xT = random.randint(x1, x2)
                yT = random.randint(y1, y2)

                #Check that starting coorindates are not near corner
                if (IsNearCorner(xT, yT)):
                    continue
                else:
                    (xA, yA) = (xT, yT)

                if (moveType == 0):  #moveType (0): maintain same position
                    (xB, yB) = (xA, yA)
                elif (moveType == 1):  #moveType (1): small move (1/3 max dist)
                    (xB, yB) = GenCoordMove(xA, yA, distSmall)
                elif (moveType == 2):  #moveType (2): large move (2/3 max dist)
                    (xB, yB) = GenCoordMove(xA, yA, distLarge)

                #Redo random generation if ending coordinates are near corner
                if (IsNearCorner(xB, yB)):
                    continue
                #Redo random generation if ending coordinates are out of bounds
                if ((xB < x1) or (xB > x2) or (yB < y1) or (yB > y2)):
                    continue
                else:
                    return (CoordMap(xA, yA), CoordMap(xB, yB))

    def SegmentImages(self):
        """Shuffles images in a folder into a list, then successively adds
        two coordinate pairs to each image. The image list is divided into 4
        sections, one for each type of trial (repeat, move small, move big, and
        opposite corners). For each section of images, the images are given a
        corresponding type of coordinate pair as governed by createPosPair()

        return: createdList, each element as: [image,<study(x,y)>,<test(x,y)>]
        """

        #Nested function - populates each division of the image list
        def SegmentFill(imageList, addingList, moveType):

            order = range(0, self.trialsPer)
            random.shuffle(order)
            for i in order:
                pospair = self.CreatePosPair(moveType)
                addingList.append(
                    [imageListSec[self.imgIdx], pospair[0], pospair[1]])
                self.imgIdx += 1
            return addingList

        imageListFull = []
        imageListSec = []

        #First put all available images into list and shuffle
        for i in os.listdir(self.imgDir):
            if i.lower().find('.jpg') != -1 and i.lower().find('PR_') == -1:
                imageListFull.append(i)
        random.shuffle(imageListFull)

        #Fill another list with the number of images per phase using prev list
        for j in range(0, self.numTrials):
            imageListSec.append(imageListFull[j])

        #Successively add each group of trials to madeImgList
        madeImgList = []
        addRepeatList = SegmentFill(imageListSec, madeImgList, 0)
        addLureSmall = SegmentFill(imageListSec, addRepeatList, 1)
        addLureLarge = SegmentFill(imageListSec, addLureSmall, 2)
        addCorners = SegmentFill(imageListSec, addLureLarge, 3)
        createdList = addCorners

        return createdList

    def ImageDiagnostic(self):
        """Draws colored dots onto the window. The dots' positions represent
        the respective location of where images will be placed throughout the
        course of the task.

        This function is to only be used as a diagnostic tool, so that one can
        get a general sense of where images might appear, without having to 
        actually run through the task. To use this function properly:
            taskSpatial = mdts.MDTS(...)
            taskSpatial.ImageDiagnostic
            #taskSpatial.RunExp()
        """
        win = self.window
        cRad = 50
        tp = self.trialsPer
        ls = self.imageList
        shapes = []
        leng = len(ls)
        for i in range(0, leng):
            color = "black"
            #print "{:<24}{:<15}{:<15}".format(img[0],img[1],img[2])
            img = ls[i]
            if i < tp:
                color = "black"
            elif (i > tp) and (i < tp * 2):
                color = "blue"
            elif (i > tp * 2) and (i < tp * 3):
                color = "orange"
            elif i > tp * 3:
                color = "green"

            shapes.append(Circle(win, radius=cRad, pos=img[1],
                                 fillColor=color))
            shapes.append(Circle(win, radius=cRad, pos=img[2],
                                 fillColor=color))
            shapes.append(
                ShapeStim(win,
                          units='pix',
                          lineWidth=5,
                          lineColor=color,
                          vertices=(img[1], img[2])))

            for shape in shapes:
                shape.draw(self.window)

            self.window.flip()
        waitKeys(keyList=['escape'])
        self.window.close()

    def RunTrial(self, image, pos):
        """Runs a particular trial, which includes displaying the image to the
        screen, and gathering the keypresses and their respective response times. 

        image: The filename of the image to display
        pos: Coordinates (on 6x4 grid) where image will be displayed
        return: tuple of first keypress info: (keyPress, reactionTime)
        """
        ShownImage = ImageStim(self.window)
        ShownImage.setPos(pos)
        ShownImage.setSize((self.imageWidth, self.imageWidth))
        ShownImage.setImage(self.imgDir + '/%s' % (image))
        ShownImage.draw(self.window)
        self.window.flip()
        clearEvents()
        self.clock.reset()
        keypresses = []
        if (self.selfPaced == False):
            wait(self.trialDuration, self.trialDuration)
            keypresses = getKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                 timeStamped=self.clock)
        elif (self.selfPaced == True):
            keypresses = waitKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                  timeStamped=self.clock)
        self.window.flip()
        wait(self.ISI)
        if len(keypresses) < 1:
            return '', 0
        return keypresses[0][0], keypresses[0][1]

    def ShowPromptAndWaitForSpace(self, prompt, keylist=['p', 'escape']):
        '''
        Show the prompt on the screen and wait for space, or the keylist specified
        returns the key pressed
        '''
        keylist = [self.pauseButton, 'escape']
        text = TextStim(self.window, prompt, color='Black')
        text.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=keylist)
        if len(continueKey) != 0 and continueKey[0] == 'escape':
            self.logfile.write("Terminated early.")
            self.logfile.close()
            sys.exit()
        return continueKey

    def RunPhase(self, phaseType):
        """Runs a phase (study or test) of the task, which includes randomizing a 
        list of images, running trials for each of those images, writing
        trial information to a logfile for each trial ran, and keeping track of
        a subject's score, based on their response to each trial. 

        phaseType: 0 -> Run Study (use starting position of image)
                   1 -> Run Test (use ending position of image)
        return: 0 -> task terminated early
                1 -> task ran to completion 
        """

        studyPrompt = (
            "Let's do the real test. \n\n Are the following objects indoor or outdoor?\n\n('{}' to continue)"
            .format(self.pauseButton))
        testPrompt = (
            "In this phase, you will see the same series of objects one at a time.\n\nAre the object locations same or new? \n\n('{}' to continue)"
            .format(self.pauseButton))
        studyText = TextStim(self.window, studyPrompt, color='Black')
        testText = TextStim(self.window, testPrompt, color='Black')

        if (phaseType == 0):
            studyText.draw(self.window)  #phaseType = 0 -> Study Phase
            self.window.flip()
            self.logfile.write("\nBegin Study\n")
        elif (phaseType == 1):
            testText.draw(self.window)  #phaseType = 1 -> Test Phase
            self.window.flip()
            self.logfile.write("\nBegin Test\n")

        log = self.logfile
        log.write("{a:<22}{b:<12}{c:<14}{d:<11}{e:<9}{f:<8}{g}\n".format(
            a='Image',
            b='Type',
            c='Start',
            d='End',
            e='Correct',
            f='Resp',
            g='RT'))

        continueKey = waitKeys(keyList=[self.pauseButton, 'escape'])
        if (continueKey[0] == 'escape'):
            self.logfile.write("\n\n\nPhase Not Run\n\n\n")
            return 0

        imgs = self.imageList
        trialOrder = range(0, len(imgs))
        random.shuffle(trialOrder)

        #Run through each trial
        for i in range(0, len(trialOrder)):

            imgIdx = trialOrder[i]
            correct = ""
            #Divide image index by the trials/cond, take floor for trial type
            trialFactor = int(math.floor(imgIdx / self.trialsPer))
            trialType = ""
            if (trialFactor == 0):
                trialType = "Same"
                if (phaseType == 1):
                    correct = self.leftButton
            elif (trialFactor == 1):
                trialType = "Small"
                if (phaseType == 1):
                    correct = self.rightButton
            elif (trialFactor == 2):
                trialType = "Large"
                if (phaseType == 1):
                    correct = self.rightButton
            elif (trialFactor == 3):
                trialType = "Crnr"
                if (phaseType == 1):
                    correct = self.rightButton

            #Display image in start position in study, end position in test
            if (phaseType == 0):
                (response, RT) = self.RunTrial(imgs[imgIdx][0],
                                               imgs[imgIdx][1])
            elif (phaseType == 1):
                (response, RT) = self.RunTrial(imgs[imgIdx][0],
                                               imgs[imgIdx][2])

            if (response == "escape"):
                self.logfile.write("\n\nPhase terminated early\n\n")
                break
            elif (response == self.pauseButton):
                self.Pause()

            #Write formatted info about trial to logfile
            log.write("{:<22}{:<9}{:<14}{:<17}{:<7}{:<6}{:>0.3f}\n".format(
                imgs[imgIdx][0], trialType, imgs[imgIdx][1], imgs[imgIdx][2],
                correct, response, RT))

            #If in test phase, tally responses, correct + incorrect answers
            if (phaseType == 1):
                if (response):
                    if (trialType == 'Same'):
                        self.scoreList[0][2] += 1
                        if (response == correct):
                            self.scoreList[0][0] += 1
                        else:
                            self.scoreList[0][1] += 1
                    elif (trialType == 'Small'):
                        self.scoreList[1][2] += 1
                        if (response == correct):
                            self.scoreList[1][0] += 1
                        else:
                            self.scoreList[1][1] += 1
                    elif (trialType == 'Large'):
                        self.scoreList[2][2] += 1
                        if (response == correct):
                            self.scoreList[2][0] += 1
                        else:
                            self.scoreList[2][1] += 1
                    elif (trialType == 'Crnr'):
                        self.scoreList[3][2] += 1
                        if (response == correct):
                            self.scoreList[3][0] += 1
                        else:
                            self.scoreList[3][1] += 1

        #Implies test phase ran through to completion
        return 1

    def SegmentPracticeImages(self, images):
        '''
        Segment practice image list into the 4 conditions and
        add two coordinate pairs to each image. Add a study coordinate location
        and test coordinate location
        
        Return:
            List [image, trialType, studyCoord(x,y), testCoord(x,y)]
        '''
        images = np.array_split(images, 4)
        allImages = []

        for idx, imageType in enumerate([0, 1, 2, 3]):
            for img in images[idx]:
                xyStudy, xyTest = self.CreatePosPair(imageType)
                allImages.append([img, imageType, xyStudy, xyTest])
        return allImages

    def RunSinglePractice(self, practiceBlock, images):
        '''
        Read in the images we want, and run the practice block for this subject
        Run encoding and test, and write to the logs 
        
        Return:
           float: ratio correct
        '''
        ### Encoding

        # imgs = [[img, trialType, Study(x,y), Test(x,y)]]
        imgs = self.SegmentPracticeImages(images)

        self.ShowPromptAndWaitForSpace(
            " Outdoor or Indoor? ('{}' to continue)".format(self.pauseButton))
        random.shuffle(imgs)

        self.logfile.write(
            "\nBegin Practice Encoding {}\n\n".format(practiceBlock))
        self.logfile.write(
            "{a:<22}{b:<12}{c:<14}{d:<11}{e:<9}{f:<8}{g}\n".format(a='Image',
                                                                   b='Type',
                                                                   c='Start',
                                                                   d='End',
                                                                   e='Correct',
                                                                   f='Resp',
                                                                   g='RT'))

        # Run the trial for each encoding trial
        for i, trial in enumerate(imgs):
            img, trialType, studyCoord, testCoord = trial
            response, RT = self.RunTrial(img, studyCoord)

            if (response == "escape"):
                self.logfile.write("\n\n Practice terminated early\n\n")
                self.logfile.close()
                sys.exit()
            elif (response == self.pauseButton):
                self.Pause()

            trialTypeMap = {0: 'Same', 1: 'Small', 2: 'Large', 3: 'Crnr'}

            trialTypeStr = trialTypeMap[trialType]
            correct = ""

            self.logfile.write(
                "{:<22}{:<9}{:<14}{:<17}{:<7}{:<6}{:>0.3f}\n".format(
                    img, trialTypeStr, studyCoord, testCoord, correct,
                    response, RT))

        ### Test
        self.ShowPromptAndWaitForSpace(
            "Is the object location same or new? ('{}' to continue)".format(
                self.pauseButton))
        random.shuffle(imgs)

        self.logfile.write(
            "\nBegin Practice Test {}\n\n".format(practiceBlock))
        self.logfile.write(
            "{a:<22}{b:<12}{c:<14}{d:<11}{e:<9}{f:<8}{g}\n".format(a='Image',
                                                                   b='Type',
                                                                   c='Start',
                                                                   d='End',
                                                                   e='Correct',
                                                                   f='Resp',
                                                                   g='RT'))

        # Keep track of the total number they got correct
        totalCorrect = 0
        for i, trial in enumerate(imgs):
            img, trialType, studyCoord, testCoord = trial
            response, RT = self.RunTrial(img, testCoord)

            if (response == "escape"):
                self.logfile.write("\n\n Practice terminated early\n\n")
                self.logfile.close()
                sys.exit()
            elif (response == self.pauseButton):
                self.Pause()

            trialTypeMap = {0: 'Same', 1: 'Small', 2: 'Large', 3: 'Crnr'}
            trialTypeStr = trialTypeMap[trialType]
            correct = self.leftButton if trialType == 0 else self.rightButton  # It should only be correct if its 'Same'

            self.logfile.write(
                "{:<22}{:<9}{:<14}{:<17}{:<7}{:<6}{:>0.3f}\n".format(
                    img, trialTypeStr, studyCoord, testCoord, correct,
                    response, RT))
            if correct == response:
                totalCorrect += 1

        # Return the percentage correct
        return totalCorrect / len(imgs)

    def RunPractice(self):
        '''
        Runs three rounds of practice trials. 
        If the participant gets a certain amount correct, they move on to the real test.
        '''

        dirFiles = os.listdir(self.imgDir)
        practiceImages = [img for img in dirFiles if "PR_" in img]
        random.shuffle(practiceImages)

        # Split the practice images into three sets
        practiceImages = np.array_split(practiceImages, 3)

        # Run each practice session
        for i in range(3):
            practicePrompt = "Let's practice.\n\n('{}' to continue)".format(
                self.pauseButton)
            self.ShowPromptAndWaitForSpace(practicePrompt)

            results = self.RunSinglePractice(
                i + 1, [img for img in practiceImages[i]])

            # If they get a certain percentage correct, then stop the practice
            self.ShowPromptAndWaitForSpace(
                "You got {}% correct! ('{}' to continue)".format(
                    int(results * 100), self.pauseButton))
            if results > .6:
                return

    def RunExp(self):
        """Run through an instance of the task, which includes the study and test
        phases. Also prints the exit message at the end, and closes the logfile
        if scores are not being written to it.

        return: (logfile, scorelist) if the test was run through. Assuming this
                happens, scores will be written to the logfile
        return: (-1,-1) if the task was quit prior to the completion of the
                study phase, meaning scores will not be writtent to the logfile
        """
        def EndExp():
            exitPrompt = ("This concludes the session. Thank you for "
                          "participating!\n\nPress Escape to quit")
            exitText = TextStim(self.window, exitPrompt, color='Black')
            exitText.draw(self.window)
            self.window.flip()
            waitKeys(keyList=['escape'])
            self.window.close()

        # Show main welcome window
        welcomePrompt = "Thank you for participating in our study! Press '{}' to begin".format(
            self.pauseButton)
        self.ShowPromptAndWaitForSpace(welcomePrompt)

        # If run practice trials, then RunPractice
        if self.runPracticeTrials:
            self.RunPractice()

        self.RunPhase(0)
        testFinished = self.RunPhase(1)
        if (testFinished):
            EndExp()
            return (self.logfile, self.scoreList)
        else:
            EndExp()
            self.logfile.close()
            return (-1, -1)
예제 #12
0
파일: __init__.py 프로젝트: peircej/ioHub
 def flip(self,clearBuffer=True):
     Window.flip(self,clearBuffer)
     return Computer.getTime()
예제 #13
0
            current_stim['duration']) + '\nBackground: ' + bg_color + ''


def t_start():
    global time_start
    time_start = kb.clock.getTime()


def t_end():
    global time_end
    time_end = kb.clock.getTime()


# begin with red rectangle
therect.draw()
my_win.flip()
wait(3)
kb.clock.reset()
therect.fillColor = bg_color  # change to the given background color at start
trialnum = 0
therect.draw()
my_win.flip()
xstart = kb.waitKeys(keyList='x')[0].rt  # start with keypress "x"

for i in range(reps):  # repeat cycle for the given number of repetitions
    shuffle(durations)
    for dur in durations:
        trialnum += 1
        current_stim['duration'] = dur
        disp_text()  # display the trial info
        therect.fillColor = stim_color  # change to given stimulus color
예제 #14
0
        pngs = map(str, pngs)

        self.masks = [ImageStim(image = img, **kwargs) for img in pngs]
        self._ix = 0

    def draw(self):
        """ Draws a single mask """
        self.masks[self._ix].draw()
        self._ix = (self._ix + 1) % len(self.masks)

        if self._ix == 0:
            shuffle(self.masks)

    def setPos(self, pos):
        """ Change the position for all masks"""
        for mask in self.masks:
            mask.setPos(pos)

if __name__ == '__main__':
    """ Demo of the dynamic mask in action """
    from psychopy import core
    from psychopy.visual import Window

    window = Window(size = (500, 500), units = 'pix', monitor = 'testMonitor')
    dynamic_mask = DynamicMask(win = window, size = (200, 200))

    for _ in xrange(25):
        dynamic_mask.draw()
        window.flip()
        core.wait(0.05)
예제 #15
0
        """ Draws a single mask """
        self.masks[self._ix].draw()
        if self.is_flicker:
            self._ix = (self._ix + 1) % len(self.masks)

            if self._ix == 0:
                shuffle(self.masks)

    def setPos(self, pos):
        """ Change the position for all masks"""
        for mask in self.masks:
            mask.setPos(pos)

    def pick_new_mask(self):
        frames = range(len(self.masks))
        self._ix = choice(frames)


if __name__ == '__main__':
    """ Demo of the dynamic mask in action """
    from psychopy import core
    from psychopy.visual import Window

    window = Window(size=(500, 500), units='pix', monitor='testMonitor')
    dynamic_mask = DynamicMask(win=window, size=(200, 200))

    for _ in xrange(25):
        dynamic_mask.draw()
        window.flip()
        core.wait(0.05)
예제 #16
0
tarscr['left']  = {}
tarscr['right'] = {}

tarscr['left']['E'] = TextStim(disp, text='E', pos=BOXCORS['left'], height=48, color=FGC)
tarscr['left']['F'] = TextStim(disp, text='F', pos=BOXCORS['left'], height=48, color=FGC)
tarscr['right']['E'] = TextStim(disp, text='E', pos=BOXCORS['right'], height=48, color=FGC)
tarscr['right']['F'] = TextStim(disp, text='F', pos=BOXCORS['right'], height=48, color=FGC)

# feedback screens
fbstim = {}
fbstim[0] = TextStim(disp, text='Incorrect', height=24, color=(1, 1, -1))
fbstim[1] = TextStim(disp, text='Correct', height=24, color=(-1, 1, -1))

# present instructions
inststim.draw()
disp.flip()
waitKeys(maxWait=float('inf'), keyList=None, timeStamped=True) # wait for key press




for cueside in ['left', "right"]:
# draw fixation mark and left and right boxes
    fixstim.draw()
    lboxstim.draw()
    rboxstim.draw()
    fixonset = disp.flip()
    wait(FIXTIME)

    fixstim.draw()
    lboxstim.draw()
예제 #17
0
    def RunButtonDiagnostic(self):
        '''
        Run a test to make sure that the buttons are being recorded correctly
        Creates a temporary window and accepts keypresses
        Shows the buttonpresses with a highlighting circle
        '''
        if (self.screenType == 'Windowed'):
            screenSelect = False
        elif (self.screenType == 'Fullscreen'):
            screenSelect = True

        window = Window(fullscr=screenSelect,
                        units='pix',
                        color='White',
                        allowGUI=False)

        indRadius = 100
        tHeight = 2 * indRadius / 5
        posC1 = (-window.size[0] / 4, 0)
        posC2 = (window.size[0] / 4, 0)
        #creating circle opjects
        circ1 = Circle(window,
                       indRadius,
                       lineColor='White',
                       lineWidth=6,
                       pos=posC1)  #training and p1 circles
        circ2 = Circle(window,
                       indRadius,
                       lineColor='White',
                       lineWidth=6,
                       pos=posC2)
        #creating text objects for cicles
        trtext1 = TextStim(window,
                           " Button 1",
                           color='White',
                           height=tHeight,
                           pos=posC1)  #training text
        trtext2 = TextStim(window,
                           " Button 2",
                           color='White',
                           height=tHeight,
                           pos=posC2)

        #List of final circle and text objects
        trCircs = [circ1, circ2]
        trTexts = [trtext1, trtext2]

        trTxt = TextStim(
            window,
            "This is a test to ensure that the buttons are being recorded correctly.\n Press each button to make sure it is being recorded correctly.\n Press escape to move on",
            pos=(0, window.size[1] / 4),
            color="Black",
            height=40,
            wrapWidth=0.8 * window.size[0])

        for circ in trCircs:
            circ.fillColor = 'Gray'
        trTxt.draw(window)
        for circ in trCircs:
            circ.draw(window)
        for text in trTexts:
            text.draw(window)
        window.flip()

        while 1:
            key = waitKeys(keyList=self.inputButtons +
                           [self.pauseButton, 'escape'])[0]

            for circ in trCircs:
                circ.fillColor = 'Gray'

            if key == 'escape' or key == self.pauseButton:
                #print "Press ecape one more time\n"
                break
            elif key == self.inputButtons[0]:
                trCircs[0].fillColor = 'Green'
            elif key == self.inputButtons[1]:
                trCircs[1].fillColor = 'Green'

            trTxt.draw(window)
            for circ in trCircs:
                circ.draw(window)
            for text in trTexts:
                text.draw(window)
            window.flip()

        window.flip()
        window.close()
예제 #18
0
# draw the incorrect feedback
fbstim['incorrect'] = (TextStim(win,
                                text='Your response was incorrect.',
                                height=24,
                                color=(1, -1, -1)))

# open a log for values
log = open(LOGFILE + '.tsv', 'w')
header = ['trial ', 'target ', 'response ', 'RT ']
headerstr = '\t'.join(header)
headerstr += '\n'
log.write(headerstr)

# show instructions
instructionsStim.draw()
win.flip()
# wait for any key
waitKeys(maxWait=float('inf'), keyList=None, timeStamped=True)

# 64 trials, randomly selected that are valid
# 12 trials that are not valid
validData = []
invalidData = []
shuffle(trialsPossible)

for trial in trialsPossible:
    # show initial screen
    fixStim.draw()
    leftboxStim.draw()
    rightboxStim.draw()
    win.flip()
예제 #19
0
tarstim['right']['congr']['L'] = ImageStim(disp, image="Rcongr_l.jpg")
tarstim['right']['incongr'] = {}
tarstim['right']['incongr']['H'] = ImageStim(disp, image="Rincongr_h.jpg")
tarstim['right']['incongr']['L'] = ImageStim(disp, image="Rincongr_l.jpg")

TARTIME = 1.7

###Feedback screen
fbstim = {}
fbstim[0] = TextStim(disp, text='Incorrect!', height=24, color='red')
fbstim[1] = TextStim(disp, text='Correct!', height=24, color='green')
fbstim[2] = TextStim(disp, text='Too slow!', height=24, color='red')
FEEDBACKTIME = 0.8

inststim.draw()
disp.flip()
waitKeys(maxWait=float('inf'), keyList=["return"], timeStamped=True)

stopwatch = core.Clock()

TRIALREPEATS = 1

alltrials1 = []
for tarside in TARSIDE:
    for congr in CONGR:
        for updown in UPDOWN:
            trial1 = {
                'tarside': tarside,
                'congr': congr,
                'updown': updown,
                'block': 1
예제 #20
0
파일: net.py 프로젝트: napratin/nap
 def flip(self, clearBuffer=True):
   Window.flip(self, clearBuffer=False)  # draw everything, but don't clear buffer yet so that we can capture it
   self.updatePygletImage()  # TODO use Window._getFrame() instead? or _getRegionOfFrame?
   if clearBuffer:
     Window.clearBuffer(self)  # now that we have captured the image, clear the buffer
예제 #21
0
class Test_textbox(object):
    def setup_class(self):
        self.win = Window([128, 128],
                          pos=[50, 50],
                          allowGUI=False,
                          autoLog=False)

    def teardown_class(self):
        self.win.close()

    def test_glyph_rendering(self):
        textbox = TextBox2(self.win,
                           "",
                           "Arial",
                           pos=(0, 0),
                           size=(1, 1),
                           letterHeight=0.1,
                           units='height')
        # Add all Noto Sans fonts to cover widest possible base of handles characters
        for font in [
                "Noto Sans", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR",
                "Noto Sans SC", "Noto Sans TC", "Niramit", "Indie Flower"
        ]:
            textbox.fontMGR.addGoogleFont(font)
        # Some exemplar text to test basic TextBox rendering
        exemplars = [
            # An English pangram
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Noto Sans",
                "screenshot": "textbox_exemplar_1.png"
            },
            # The same pangram in IPA
            {
                "text":
                "ə saɪkəʊpaɪ zɛlət nəʊz ə smidge ɒv wx, bʌt ˈʤɑːvəskrɪpt ɪz ðə ˈkwɛsʧən",
                "font": "Noto Sans",
                "screenshot": "textbox_exemplar_2.png"
            },
            # The same pangram in Hangul
            {
                "text": "아 프시초피 제알롣 크노W스 아 s믿게 오f wx, 붇 자v앗c립t 잇 테 q왯디온",
                "font": "Noto Sans KR",
                "screenshot": "textbox_exemplar_3.png"
            },
            # A noticeably non-standard font
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Indie Flower",
                "screenshot": "textbox_exemplar_4.png",
            }
        ]
        # Some text which is likely to cause problems if something isn't working
        tykes = [
            # Text which doesn't render properly on Mac (Issue #3203)
            {
                "text": "कोशिकायें",
                "font": "Noto Sans",
                "screenshot": "textbox_tyke_1.png"
            },
            # Thai text which old Text component couldn't handle due to Pyglet
            {
                "text": "ขาว แดง เขียว เหลือง ชมพู ม่วง เทา",
                "font": "Niramit",
                "screenshot": "textbox_tyke_2.png"
            }
        ]
        # Test each case and compare against screenshot
        for case in exemplars + tykes:
            textbox.reset()
            textbox.fontMGR.addGoogleFont(case['font'])
            textbox.font = case['font']
            textbox.text = case['text']
            self.win.flip()
            textbox.draw()
            if case['screenshot']:
                # Uncomment to save current configuration as desired
                #self.win.getMovieFrame(buffer='back').save(Path(utils.TESTS_DATA_PATH) / case['screenshot'])
                utils.compareScreenshot(
                    Path(utils.TESTS_DATA_PATH) / case['screenshot'], self.win)

    def test_colors(self):
        textbox = TextBox2(self.win,
                           "",
                           "Consolas",
                           pos=(0, 0),
                           size=(1, 1),
                           letterHeight=0.1,
                           units='height',
                           colorSpace="rgb")
        textbox.fontMGR.addGoogleFont("Noto Sans")
        textbox.font = "Noto Sans"
        textbox.text = "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question."
        # Some exemplar text to test basic colors
        exemplars = [
            # White on black in rgb
            {
                "color": (1, 1, 1),
                "fillColor": (-1, -1, -1),
                "borderColor": (-1, -1, -1),
                "space": "rgb",
                "screenshot": "textbox_colors_WOB.png"
            },
            # White on black in named
            {
                "color": "white",
                "fillColor": "black",
                "borderColor": "black",
                "space": "rgb",
                "screenshot": "textbox_colors_WOB.png"
            },
            # White on black in hex
            {
                "color": "#ffffff",
                "fillColor": "#000000",
                "borderColor": "#000000",
                "space": "hex",
                "screenshot": "textbox_colors_WOB.png"
            },
        ]
        # Some colors which are likely to cause problems if something isn't working
        tykes = [
            # Text only
            {
                "color": "white",
                "fillColor": None,
                "borderColor": None,
                "space": "rgb",
                "screenshot": "textbox_colors_tyke1.png"
            },
            # The following will only work when the Color class is implemented (currently opacity is all or nothing)
            # Fill only
            # {"color": None, "fillColor": "white", "borderColor": None, "space": "rgb",
            #  "screenshot": "textbox_colors_tyke2.png"},
            # Border only
            # {"color": None, "fillColor": None, "borderColor": "white", "space": "rgb",
            # "screenshot": "textbox_colors_tyke3.png"},
        ]
        # Test each case and compare against screenshot
        for case in exemplars + tykes:
            # Raise error if case spec does not contain all necessary keys
            if not all(
                    key in case for key in
                ["color", "fillColor", "borderColor", "space", "screenshot"]):
                raise KeyError(
                    f"Case spec for test_colors in class {self.__class__.__name__} ({__file__}) invalid, test cannot be run."
                )
            # Apply params from case spec
            textbox.colorSpace = case['space']
            textbox.color = case['color']
            textbox.fillColor = case['fillColor']
            textbox.borderColor = case['borderColor']
            self.win.flip()
            textbox.draw()
            if case['screenshot']:
                # Uncomment to save current configuration as desired
                # self.win.getMovieFrame(buffer='back').save(Path(utils.TESTS_DATA_PATH) / case['screenshot'])
                utils.compareScreenshot(
                    Path(utils.TESTS_DATA_PATH) / case['screenshot'], self.win)
    deckDTitleText.color = "white"

    #draw the deckTitle elements
    deckATitleText.draw()
    deckBTitleText.draw()
    deckCTitleText.draw()
    deckDTitleText.draw()

    #draw the variable elements
    winningsVariableText.draw()
    amountLostVariableText.draw()
    amountWonVariableText.draw()


drawMainUI()
display.flip()

#       ♔ Main Code


def runningTrial(char_pressed):
    pass


char_pressed = psychopy.event.waitKeys()

while char_pressed != ['q'] and True:
    #This is a sentinel controlled while loop, it'll break when the user quits or we run out of rows

    if deckA.rowNumber > (
            deckA.getTotalRows() -
예제 #23
0
userResponse(
    '', False, qpos, 'images/Hello.gif'
)  # call the userResponse -> double while loop to save the user taped response

# ----------------------------------- #
# SETTING FOR THE PRE-TEST            #
# WHILE THE PRE-TEST IS NOT SUCCEEDED #
# ----------------------------------- #
response = ''  # the response attempted by the user - On commence avec une réponse vide
while response != pretest:  # while the answer is not correct
    response = ''  # the response written by the user - On commence avec une chaîne vide
    respstim = TextStim(disp, text='', pos=qpos, height=size,
                        color=color)  # stimulus texte
    qstim = ImageStim(disp, image='images/TradVonat.gif')
    qstim.draw()  # dessiner la question
    disp.flip()  # passer au screen au suivant -> on met la question par-dessus
    core.wait(
        loadTime)  # delay of 10 seconds before passing to the learning phase
    response, done = tapeAnswer(
        response, False, False)  # While loop to taping the entire answer

    # ------------------------------------------------------- #
    # CHECK IF THE PRETEST IS SUCCEEDED OR NOT                #
    # DISPLAY A MESSAGE TO THE USER ACCORDING TO THE ANSWER   #
    # ------------------------------------------------------- #
    if response == pretest:  # if the answer is correct
        userResponse(
            '', False, qpos, 'images/BravoVonat.gif'
        )  # call the userResponse -> double while loop to save the user taped response
    else:  # if the answer is NOT correct
        userResponse(
예제 #24
0
			N_types.append(2) #another quarter shows target on the right
			N_types.append(3) #another: foils on the left
			N_types.append(4) #another: foils on the right
else: #if it's neither of these 2 tasks
	while i < N_trials:
		N_types.append(5) #on all trials, stimuli are presented in the middle of the screen

i = 0
while i < N_blanks:
	N_types.append(9) #then, we add the blank trials (if there are any)
shuffle(N_types) #And finally, randomize the order of trials


'''Actual implementation of the experiment'''
welcome_txt.draw()
win.flip()
waitKeys(keyList=[button_welcome_quit]) #display the welcome text, til people want to continue

clearEvents()	#makes sure that pressing the quit button before trial onset is ignored

for trial_number in len(N_types): #for every trial that is implemented
	quitkey = getKeys(keyList = [button_quit]) #check if the quit button has been pressed last trial
	if len(quitkey) > 0: #if that's the case,
		break #stop the experiment (or at least, the trials / for-loop)

	if	N_types[trial_number] < 5: #if the stimuli is supposed to be shown non-centrally (indicated by trial_type index)
		if	N_types[trial_number] % 2 ==1: #if they're supposed to be shown left (i.e., their index is an odd number)
			example_mask.setPos(left) #all pictures are shown left
			example_target.setPos(left)
			example_foil.setPos(left)
		else: #if they're supposed to be shown on the right
예제 #25
0
def run(window: visual.Window) -> pd.DataFrame:
    # Get ready screen
    fixate(
        window,
        "Find the arrow keys, and begin fixating now.\n\nThe first trial is about to begin.",
    )

    # TODO: Make sure clocks are handled correctly
    # create a clock for rt's
    clock = core.Clock()

    # TODO: Add more sources of text/code

    # Source of files: https://web.eecs.umich.edu/~weimerw/fmri.html
    # Direct link: https://web.eecs.umich.edu/~weimerw/fmri-resources/2016-materials.zip
    image_path = Path("~/.eegnb/tmp/").expanduser()
    if not image_path.exists():
        print("Images not found, downloading...")
        image_path.mkdir(parents=True)
        download_images(image_path)
        print("Done!")

    img_path = image_path / "materials.final"
    assert img_path.exists()

    code_imgs = (img_path / "comp").glob("*.png")
    prose_imgs = (img_path / "prose" / "bugs").glob("*.PNG")

    # Setup log
    trials = pd.DataFrame(
        [["code", img] for img in code_imgs] + [["prose", img] for img in prose_imgs],
        columns=["type", "image_path"],
    )

    # Shuffle trials
    trials = sklearn.utils.shuffle(trials)

    # saving trial information for output
    responses: List[dict] = []

    for ii, trial in trials.iterrows():
        print(
            f"Trial {ii}: stimuli type '{trial['type']}' (image {trial['image_path']})"
        )

        image = visual.ImageStim(win=window, image=trial["image_path"])
        image.draw()

        window.flip()
        t_presented = clock.getTime()
        t_presented_utc = time()

        core.wait(0.1)
        keys = event.waitKeys(keyList=["up", "down", "space"], timeStamped=clock)
        t_answered = clock.getTime()
        t_answered_utc = time()

        responses.append(
            {
                "type": trial["type"],
                "image_path": trial["image_path"],
                "response": keys[0][0],
                "t_presented": t_presented,
                "t_presented_utc": t_presented_utc,
                "t_answered": t_answered,
                "t_answered_utc": t_answered_utc,
            }
        )

        fixate(window, "Relax\n\nThe next trial will start soon")

    return pd.DataFrame(responses)
def main():
    # I set up my siplay size and background colour
    DISPSIZE = (1400, 800)
    BGC = (-1, -1, -1)

    # for my game I need to create some variables:
    score = 0
    lives = 3
    level = 1
    mouse_x = 0
    mouse_y = 0

    # I create some objects:
    win = Window(size=DISPSIZE, units='pix', fullscr=False, color=BGC)

    mouse = Mouse(win)

    target = ImageStim(win, 'target.png', size=(420, 420))

    # I will display three text stimuli to the player while playing the game:
    lives_count = TextStim(
        win,
        text=f'Lives = {lives}',
        height=35,
        color=(1, 0.2, 0.6),
        pos=(100, 330),
    )

    score_count = TextStim(win,
                           text=f'Score = {score}',
                           height=35,
                           color=(0.2, 0.2, 0.8),
                           pos=(450, 330))

    level_count = TextStim(win,
                           text=f'Level = {level}',
                           height=35,
                           color=(1, -0.5, 1),
                           pos=(850, 330))

    # I define the messages to show the player the outcome of the game:
    you_have_lost = TextStim(
        win,
        text='Boo! Not a great game, pal... Get it together!',
        height=35,
        color=(0.2, 0.2, 0.8),
        pos=(250, 230))

    you_have_won = TextStim(win,
                            text='Yey! Well done, champ! Time to celebrate!',
                            height=35,
                            color=(0.2, 0.2, 0.8),
                            pos=(250, 230))

    # These are the images I use for the winning and loosing scenarios:
    looser = ImageStim(win, 'failed.jpg', pos=(0, -100), size=(420, 420))
    winner = ImageStim(win, 'tiny_trash.jpg', pos=(0, -100), size=(420, 420))

    # I introduce this dialog to save the user's ID:
    user_id_dialog = gui.Dlg(title="Target Game")
    user_id_dialog.addText('Please write your subject ID: a 4-digit code')
    user_id_dialog.addField('Subject ID:')
    ok_data = user_id_dialog.show()  # show dialog and wait for OK or Cancel

    if not user_id_dialog.OK:
        print('user cancelled')

    # NOW THE GAME WILL START:

    # If enabled, intro will play:
    enable_intro = True

    if enable_intro:
        show_intro(win)

    # We create this list to save our results into
    target_hits_per_level = [
        [],
        [],
        [],
        [],
    ]

    move_target_at_random_pos(
        target)  # first the target is shown on the screen

    lives_timer = CountdownTimer(
        5)  # Level 1 starts with 5 sec to hit the target
    mouse_click_clock = Clock()
    reaction_time_clock = Clock()
    change_target = False

    while level < 4 and lives > 0:
        target.draw()
        target_x, target_y = target.pos
        lives_count.draw()
        score_count.draw()
        level_count.draw()

        win.flip()

        keys_pressed = getKeys()
        if 'q' in keys_pressed:
            break
        mouse_is_pressed = mouse.getPressed()[0] == True

        mouse_x, mouse_y = mouse.getPos()
        level_count.setText(f'Level = {level}')

        #if the player does not click, the target moves and the player looses a life
        if lives_timer.getTime() <= 0:
            lives -= 1
            lives_count.setText(f'Lives = {lives}')
            mouse_in_target = None
            mouse_in_target_x = None
            mouse_in_target_y = None
            change_target = True

        # Check for a mouse click every 0.2s, so that we don't accept more than 1
        # press on mouse hold
        if mouse_is_pressed and mouse_click_clock.getTime() > 0.2:
            mouse_click_clock.reset()
            change_target = True

            if mouse_clicked_in_target(mouse, target):
                mouse_in_target = True
                mouse_in_target_x = mouse_x - target_x
                mouse_in_target_y = mouse_y - target_y
                score += 1
                score_count.setText(f'Score = {score}')

            else:
                lives -= 1
                lives_count.setText(f'Lives = {lives}')
                mouse_in_target = False
                mouse_in_target_x = None
                mouse_in_target_y = None

        if change_target:

            mouse_click = {
                'mouse_x': mouse_in_target_x,
                'mouse_y': mouse_in_target_y,
                'reaction_time': reaction_time_clock.getTime(),
                'mouse_in_target': mouse_in_target,
            }

            target_hits_per_level[level - 1].append(
                mouse_click)  # inddexes start from 0 --> level - 1

            if score == 5:
                lives_timer.reset(3)
                level = 2
            elif score == 10:
                lives_timer.reset(1)
                level = 3
            elif score == 15:
                level = 4

            move_target_at_random_pos(target)
            lives_timer.reset()
            reaction_time_clock.reset()
            change_target = False

    # Here we display the outcome of the game:
    if level == 4:
        you_have_won.draw()
        winner.draw()
    else:
        you_have_lost.draw()
        looser.draw()

    win.flip()
    wait(3)

    # Finally, we draw the overwivew for thr player

    draw_overview_target(
        win=win,
        level=1,
        target_pos=(-450, 0),
        text_pos=(50, 300),
        mouse_clicks_all_levels=target_hits_per_level,
    )

    draw_overview_target(
        win=win,
        level=2,
        target_pos=(0, 0),
        text_pos=(450, 300),
        mouse_clicks_all_levels=target_hits_per_level,
    )

    draw_overview_target(
        win=win,
        level=3,
        target_pos=(450, 0),
        text_pos=(850, 300),
        mouse_clicks_all_levels=target_hits_per_level,
    )

    win.flip()
    wait(4)

    # The user has not clicked Cancel on the subject ID window
    if ok_data is not None:
        write_results(target_hits_per_level, 'results-' + ok_data[0] + '.csv')

    win.close()
예제 #27
0
파일: mdtt.py 프로젝트: yassalab/MDT-Suite
class MDTT(object):
    def __init__(self, logfile, imgDir, subjectNum, screenType, numStim,
                 numBlocks, trialDuration, ISI, selfPaced, runPractice,
                 inputButtons, pauseButton):

        self.logfile = logfile
        self.imgDir = imgDir
        self.subjectNum = subjectNum
        self.numStim = numStim
        self.numBlocks = numBlocks
        self.trialDuration = trialDuration
        self.selfPaced = selfPaced
        self.ISI = ISI
        self.numCats = 4
        self.trialsPer = int((self.numStim / self.numCats) / 2)
        self.runPractice = runPractice
        self.leftButton = inputButtons[0]
        self.rightButton = inputButtons[1]
        self.pauseButton = pauseButton

        #Set up window, center, left and right image sizes + positions

        if (screenType == 'Windowed'):
            screenSelect = False
        elif (screenType == 'Fullscreen'):
            screenSelect = True

        self.window = Window(fullscr=screenSelect,
                             units='pix',
                             color='White',
                             allowGUI=False)
        self.imageWidth = self.window.size[1] / 5.5
        self.centerImage = ImageStim(self.window)
        self.centerImage.setSize((self.imageWidth, self.imageWidth))
        self.leftImage = ImageStim(self.window)
        self.leftImage.setPos((-1.5 * self.imageWidth, 0))
        self.leftImage.setSize((self.imageWidth, self.imageWidth))
        self.rightImage = ImageStim(self.window)
        self.rightImage.setPos((1.5 * self.imageWidth, 0))
        self.rightImage.setSize((self.imageWidth, self.imageWidth))
        self.clock = Clock()

        #Init score list for 4 categories: [correct,incorrect,response]
        self.scoreList = []
        for i in range(0, 4):
            self.scoreList.append([0, 0, 0])

    def SplitRange(self, rangeMin, rangeMax, start=0):
        """Creates a pair of indexes separated by a value. The value itself
        can be between a min-max range. Neither index can be an index that is
        in a list of already used indexes.

        rangeMin: minimum amount that indexes can be separated by
        rangeMax: maximum amount that indexes can be separated by
        start: start index of used list 
        return: a pair of indexes (index1,index2)
                (-1,-1) if range split failed
        """

        #Search through list of used indexes to ensure no duplicates
        #Ignore start/end of list, as it's already used by primacy/recency
        for i in range(0, self.numStim):
            if (i in self.usedList):
                continue
            added = random.randint(rangeMin, rangeMax)
            startPt = added
            searchedRange = False
            #Loop through the min to max range of added values
            while not searchedRange:
                if ((i + added < self.numStim)
                        and (i + added not in self.usedList)):
                    self.usedList.append(i)
                    self.usedList.append(i + added)
                    return (i, i + added)
                if (added > rangeMin):
                    added -= 1
                else:
                    added = rangeMax
                if (added == startPt):
                    searchedRange = True
        return (-1, -1)

    def CreatePairsSpaced(self):
        """Creates a list, each element containing two indexes as well as a
        trial type. The trial type is based upon the spacing of the indexes as
        follows:

        adjacent (1): numbers next to eachother e.g. (3,4) or (8,9)
        eightish (2): numbers separated by between 7-9 e.g. (5,12) or (14,23)
        sixteenish (3): numbers separated by between 15-17 e.g. (3,18) or (8,25)
        primacy/recency: (4): start and end of list numbers e.g. (1,30) or (0,31)

        Occassionally, the list will fail to successfully split into index pairs.
        (SplitRange() returns (-1,-1) when this happens). The function will retry 
        the index splitting until all indexes are used

        return: list containing elements each with: (index1,index2,trialType)
        """

        startList = range(0, self.trialsPer)
        endList = range(self.numStim - self.trialsPer, self.numStim)
        trialOrder = range(0, (self.trialsPer * 3))  #3 categories besides P/R
        random.shuffle(startList)
        random.shuffle(endList)

        #Attempt to split 0-31 range into 4 index categories
        #Split fails if any one of the index pairs is (-1,-1) at end
        def AttemptSplit():

            # 3 categories besides P/R
            trialOrder = range(0, (self.trialsPer * 3))
            random.shuffle(trialOrder)
            self.usedList = []
            attemptList = []
            finalList = []

            #Add edge index pairs (primacy/recency)
            for i in range(0, self.trialsPer):
                finalList.append((startList[i], endList[i], 4))
                self.usedList.append(startList[i])
                self.usedList.append(endList[i])

            #Add spaced (separated) pairs of indexes to list
            for trial in trialOrder:
                if (trial % 3 == 0):  #Adjacent
                    (idxOne, idxTwo) = self.SplitRange(1, 1)
                    attemptList.append((idxOne, idxTwo, 1))
                elif (trial % 3 == 1):  #Eightish
                    (idxOne, idxTwo) = self.SplitRange(7, 9)
                    attemptList.append((idxOne, idxTwo, 2))
                elif (trial % 3 == 2):  #Sixteenish
                    (idxOne, idxTwo) = self.SplitRange(15, 17)
                    attemptList.append((idxOne, idxTwo, 3))

            #Ensures PR trials (type 4) occur first. Randomize successive trials
            random.shuffle(attemptList)
            finalList.extend(attemptList)
            return finalList

        #Try AttemptSplit() until index split is successful
        splitSuccess = False
        while (not splitSuccess):
            splitList = AttemptSplit()
            foundError = False
            for pair in splitList:
                if ((pair[0] == -1) or (pair[1] == -1)):
                    foundError = True
            if (foundError == True):
                continue
            else:
                splitSuccess = True

        return splitList

    def RunTrialSingle(self, img):
        """Displays a single image at the center of the screen for a period of
        time, and captures keypresses and their respective reaction times.

        img: the image to Displays
        return: a list of keypresses and respective reaction times
        """
        self.centerImage.setImage(self.imgDir + "/%s" % (img))
        self.centerImage.draw(self.window)
        clearEvents()
        self.window.flip()
        self.clock.reset()
        keyPresses = []
        if (self.selfPaced == False):
            wait(self.trialDuration, self.trialDuration)
            keyPresses = getKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                 timeStamped=self.clock)
        elif (self.selfPaced == True):
            keyPresses = waitKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                  timeStamped=self.clock)
        self.window.flip()
        wait(self.ISI)
        return keyPresses

    def RunTrialDual(self, leftImg, rightImg):
        """Displays two images on the screen for a period of time, and captures
        keypresses and their respective reaction times.

        leftimg: the image to display on the left
        rightimg: the image to display on the right
        return: a list of keypresses and respective reaction times
        """
        self.leftImage.setImage(self.imgDir + "/%s" % (leftImg))
        self.rightImage.setImage(self.imgDir + "/%s" % (rightImg))
        self.leftImage.draw(self.window)
        self.rightImage.draw(self.window)
        clearEvents()
        self.window.flip()
        self.clock.reset()
        if (self.selfPaced == False):
            wait(self.trialDuration, self.trialDuration)
            keyPresses = getKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                 timeStamped=self.clock)
        elif (self.selfPaced == True):
            keyPresses = waitKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, "escape"
            ],
                                  timeStamped=self.clock)
        self.window.flip()
        wait(self.ISI)
        return keyPresses

    def RunStudy(self, imageBlock, session):
        """Runs the study, i.e. the first half of each experimental block.
        Writes all relevant information about the study to a logfile.

        imageBlock: List of images to display during the study
        session: the number of the session (block number) that is running
        """
        studyPrompt = (
            "Test Session {}/{}: Are the following objects indoor or outdoor?\n\n('{}' to continue)"
            .format(session, 10, self.pauseButton))
        studyText = TextStim(self.window, studyPrompt, color='Black')
        studyText.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=[self.pauseButton, 'escape'])

        if (continueKey[0] == 'escape'):
            self.logfile.write("\n\n\nStudy Not Run Early\n\n\n")
            return

        self.logfile.write("\nBegin Study %d\n" % (session))
        self.logfile.write("{h1:<6}{h2:<23}{h3:<10}{h4}\n".format(
            h1="Trial", h2="Image", h3="Response", h4="RT"))

        #Run trial for each image in the image block
        for i in range(0, len(imageBlock)):
            keyPresses = self.RunTrialSingle(imageBlock[i])
            if (keyPresses == []):
                respKey = ''
                respRT = 0
            else:
                respKey = keyPresses[0][0]
                respRT = keyPresses[0][1]
            if (respKey == "escape"):
                self.logfile.write("\n\n\nStudy block terminated early\n\n\n")
                break
            elif (respKey == self.pauseButton):
                self.Pause()

            self.logfile.write("{:^5}{:<23}{:^11}{:<1.3f}\n".format(
                i + 1, imageBlock[i], respKey, respRT))

        return

    def RunTest(self, imageBlock, pairList, session):
        """Runs the test, i.e. the second half of each experimental block.
        Wites all relevant information about the test to a logfile

        imageBlock: List of images to display during the test
        pairList: List of paired image indexes w/ trial type
        session: the number of the session (block number) that is running
        """
        testPrompt = (
            "In this phase, the same series of objects will be shown\n\nWhich came first: Left or Right?\n\n('{}' to continue)"
            .format(self.pauseButton))
        testText = TextStim(self.window, testPrompt, color='Black')
        testText.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=[self.pauseButton, 'escape'])

        if (continueKey[0] == 'escape'):
            self.logfile.write("\n\n\nTest Not Run\n\n\n")
            return 0

        self.logfile.write("\nBegin Test %d\n" % (session))
        lghead = "{a:<7}{b:<7}{c:<23}{d:<23}{e:<7}{f:<7}{g:<10}{h:<7}{i}\n".format(
            a="Trial",
            b="TType",
            c="LeftImage",
            d="RightImage",
            e="LNum",
            f="RNum",
            g="CorResp",
            h="Resp",
            i="RT")
        self.logfile.write(lghead)

        #Randomize if pair is shown: (bef > aft) or (aft > bef) order
        sideOrder = range(0, len(pairList))
        random.shuffle(sideOrder)
        correct = ''
        keyPresses = []

        #Run dual image trial for each pair in the pairlist
        for i in range(0, len(pairList)):
            trialNum = i + 1
            trialType = pairList[i][2]
            firstIdx = pairList[i][0]
            secondIdx = pairList[i][1]
            firstImg = imageBlock[pairList[i][0]]
            secondImg = imageBlock[pairList[i][1]]

            #Preserve the order images were shown in
            if (sideOrder[i] % 2 == 0):
                correct = self.leftButton
                leftIdx = firstIdx
                rightIdx = secondIdx
                leftImg = firstImg
                rightImg = secondImg
                keyPresses = self.RunTrialDual(leftImg, rightImg)
            #Reverse order images were shown
            elif (sideOrder[i] % 2 == 1):
                correct = self.rightButton
                leftIdx = secondIdx
                rightIdx = firstIdx
                leftImg = secondImg
                rightImg = firstImg
                keyPresses = self.RunTrialDual(leftImg, rightImg)

            #Get first response, or set to none if no response
            if (keyPresses == []):
                respKey = ''
                respRT = 0
            else:
                respKey = keyPresses[0][0]
                respRT = keyPresses[0][1]
            #Break out of image block with escape, break out of program with f5
            if (respKey == 'escape'):
                self.logfile.write("\n\nTest block terminated early\n\n")
                break
            elif (respKey == self.pauseButton):
                self.Pause()

            #Keep track of score
            if (respKey):
                self.scoreList[pairList[i][2] - 1][2] += 1
                if (respKey == correct):
                    self.scoreList[pairList[i][2] - 1][0] += 1
                else:
                    self.scoreList[pairList[i][2] - 1][1] += 1

            #Write info to logfile
            lgspace = "{:^5}{:^9}{:<23}{:<23}{:<7}{:<10}{:<8}{:<6}{:<1.3f}\n"
            lgform = (lgspace.format(trialNum, trialType, leftImg, rightImg,
                                     leftIdx, rightIdx, correct, respKey,
                                     respRT))
            self.logfile.write(lgform)

        return 1

    def Pause(self):
        """Pauses the task, and displays a message waiting for a spacebar
        input from the user before continuing to proceed.
        """
        pauseMsg = "Experiment Paused\n\nPress '{}' to continue".format(
            self.pauseButton)
        pauseText = TextStim(self.window,
                             text=pauseMsg,
                             color='Black',
                             height=40)
        pauseText.draw(self.window)
        self.window.flip()
        waitKeys(keyList=[self.pauseButton])
        clearEvents()

    def SegmentPracticeImages(self, images):
        '''
        Return the indexes for the test, it will index the image list from study:
            [[index_left_image, index_right_image, trialType]]
        '''
        # Since we know that the images are already randomized, we can just iterate over them
        # In order for the code to work, we want 4 practice images per practice block
        if len(images) != 4:
            print "Assertion error: length of practice images is not equal to 4"
            self.window.close()
            sys.exit()

        # Trial type of 4 means long distance
        large_dist = (0, 3, 4) if random.random() > .5 else (3, 0, 4)
        mid_dist_1 = (0, 2, 2) if random.random() > .5 else (2, 0, 2)
        mid_dist_2 = (1, 3, 2) if random.random() > .5 else (3, 1, 2)
        adjacent = (0, 1, 1) if random.random() > .5 else (1, 0, 1)
        adjacent_2 = (1, 2, 1) if random.random() > .5 else (2, 1, 1)
        adjacent = adjacent if random.random() > .5 else adjacent_2

        all = [large_dist, mid_dist_1, mid_dist_2, adjacent]
        random.shuffle(all)

        return all

    def ShowPromptAndWaitForSpace(self, prompt, keylist=['space', 'escape']):
        '''
        Show the prompt on the screen and wait for space, or the keylist specified
        returns the key pressed
        '''
        keylist = [self.pauseButton, 'escape']
        text = TextStim(self.window, prompt, color='Black')
        text.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=keylist)
        if len(continueKey) != 0 and continueKey[0] == 'escape':
            self.logfile.write("Terminated early.")
            self.logfile.close()
            sys.exit()
        return continueKey

    def RunSinglePractice(self, practiceBlock, imgs):
        '''
        Read in the images we want, and run the practice block for this subject
        Run encoding and test, and write to the logs 
        
        Return:
           float: ratio correct
        '''
        random.shuffle(imgs)

        ### Encoding
        # imgs = [[img, trialType, Study(x,y), Test(x,y)]]
        testIdxs = self.SegmentPracticeImages(imgs)

        self.ShowPromptAndWaitForSpace(
            " Indoor or Outdoor?\n\n('{}' to continue)".format(
                self.pauseButton))

        self.logfile.write("\nBegin Practice Study {}\n".format(practiceBlock))
        self.logfile.write("{h1:<6}{h2:<23}{h3:<10}{h4}\n".format(
            h1="Trial", h2="Image", h3="Response", h4="RT"))

        # Run the trial for each encoding trial
        for i in range(0, len(imgs)):
            keyPresses = self.RunTrialSingle(imgs[i])
            if (keyPresses == []):
                respKey = ''
                respRT = 0
            else:
                respKey = keyPresses[0][0]
                respRT = keyPresses[0][1]
            if (respKey == "escape"):
                self.logfile.write("\n\n\nStudy block terminated early\n\n\n")
                break
            elif (respKey == self.pauseButton):
                self.Pause()

            self.logfile.write("{:^5}{:<23}{:^11}{:<1.3f}\n".format(
                i + 1, imgs[i], respKey, respRT))

        ### Test
        self.ShowPromptAndWaitForSpace(
            " Which came first? Left or right? ('{}' to continue)".format(
                self.pauseButton))

        self.logfile.write("\nBegin Practice Test {}\n".format(practiceBlock))
        self.logfile.write(
            "{a:<7}{b:<7}{c:<23}{d:<23}{e:<7}{f:<7}{g:<10}{h:<7}{i}\n".format(
                a="Trial",
                b="TType",
                c="LeftImage",
                d="RightImage",
                e="LNum",
                f="RNum",
                g="CorResp",
                h="Resp",
                i="RT"))

        # Keep track of the total number they got correct
        totalCorrect = 0
        for trialNum, idxes in enumerate(testIdxs):
            leftImgIdx, rightImgIdx, trialType = idxes

            leftImg = imgs[leftImgIdx]
            rightImg = imgs[rightImgIdx]

            keyPresses = self.RunTrialDual(leftImg, rightImg)
            correct = self.leftButton if leftImgIdx < rightImgIdx else self.rightButton

            #Get first response, or set to none if no response
            if (keyPresses == []):
                respKey = ''
                respRT = 0
            else:
                respKey = keyPresses[0][0]
                respRT = keyPresses[0][1]
            #Break out of image block with escape, break out of program with f5
            if (respKey == 'escape'):
                self.logfile.write("\n\nPractice block terminated early\n\n")
                self.logfile.close()
                sys.exit()

            #Write info to logfile
            lgspace = "{:^5}{:^9}{:<23}{:<23}{:<7}{:<10}{:<8}{:<6}{:<1.3f}\n"
            lgform = (lgspace.format(trialNum + 1, trialType, leftImg,
                                     rightImg, leftImgIdx, rightImgIdx,
                                     correct, respKey, respRT))
            self.logfile.write(lgform)

            if respKey == correct:
                totalCorrect += 1

        # Return the percentage correct
        return totalCorrect / len(imgs)

    def RunPractice(self):
        '''
        Runs three rounds of practice trials. 
        If the participant gets a certain amount correct, they move on to the real test.
        '''

        dirFiles = os.listdir(self.imgDir)
        practiceImages = [img for img in dirFiles if "PR_" in img]
        if len(practiceImages) == 0:
            print "No practice images found"
            self.window.close()
            sys.exit()

        random.shuffle(practiceImages)

        # Split the practice images into three sets
        practiceImages = np.array_split(practiceImages, 3)

        # Run each practice session
        for i in range(3):
            practicePrompt = "Let's practice\n\n('{}' to continue)".format(
                self.pauseButton)
            self.ShowPromptAndWaitForSpace(practicePrompt)

            results = self.RunSinglePractice(
                i + 1, [img for img in practiceImages[i]])

            # If they get a certain percentage correct, then stop the practice
            self.ShowPromptAndWaitForSpace(
                "You got {}% correct! ('{}' to continue)".format(
                    int(results * 100), self.pauseButton))
            if results > .6:
                return

    def RunExp(self):
        """Runs through an instance of the MDT-T experiment, which includes
        arranging the images into lists/sublists, running through a given
        number of study/test blocks, and writing the scores to a logfile. 
        """

        #Print task ending message to the screen; wait for user to press escape
        def EndExp():
            exitPrompt = ("This concludes the session. Thank you for "
                          "participating!\n\nPress Escape to quit")
            exitText = TextStim(self.window, exitPrompt, color='Black')
            exitText.draw(self.window)
            self.window.flip()
            waitKeys(keyList=['escape'])
            self.window.close()

        # Run practice
        if self.runPractice:
            self.RunPractice()

        #Put image files from folder into list
        imageList = []
        for img in os.listdir(self.imgDir):
            if (
                    img[-4:] == ".jpg" and "PR_" not in img
            ):  # Make sure that PR (practice image) is not included for study/tests
                imageList.append(img)
        random.shuffle(imageList)

        #Divide imagelist into <numBlocks> # of lists, put into one list
        #Each sublist contains <numStim> # of stimuli
        imageBlockList = []
        for i in range(0, self.numBlocks):
            block = []
            for j in range(i * self.numStim,
                           self.numStim + (i * self.numStim)):
                block.append(imageList[j])
            imageBlockList.append(block)

        #Run through each study/test block
        blockOrder = range(0, self.numBlocks)
        random.shuffle(blockOrder)
        writeScores = True
        for i in range(0, len(blockOrder)):
            pairList = self.CreatePairsSpaced()
            self.RunStudy(imageBlockList[i], i + 1)
            testFinished = self.RunTest(imageBlockList[i], pairList, i + 1)
            if not testFinished:
                writeScores = False
                continue

        EndExp()
        #Return logfile and scorelist if all study/test blocks gone through
        if writeScores:
            return (self.logfile, self.scoreList)
        else:
            return (-1, -1)
예제 #28
0
class Test_textbox(object):
    def setup_class(self):
        self.win = Window([128, 128],
                          pos=[50, 50],
                          allowGUI=False,
                          autoLog=False)

    def teardown_class(self):
        self.win.close()

    def test_glyph_rendering(self):
        textbox = TextBox2(self.win,
                           "",
                           "Arial",
                           pos=(0, 0),
                           size=(1, 1),
                           letterHeight=0.1,
                           units='height')
        # Add all Noto Sans fonts to cover widest possible base of handles characters
        textbox.fontMGR.addGoogleFonts([
            "Noto Sans", "Noto Sans HK", "Noto Sans JP", "Noto Sans KR",
            "Noto Sans SC", "Noto Sans TC", "Niramit", "Indie Flower"
        ])
        # Some exemplar text to test basic TextBox rendering
        exemplars = [
            # An English pangram
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Noto Sans",
                "screenshot": "textbox_exemplar_1.png"
            },
            # The same pangram in IPA
            {
                "text":
                "ə saɪkəʊpaɪ zɛlət nəʊz ə smidge ɒv wx, bʌt ˈʤɑːvəskrɪpt ɪz ðə ˈkwɛsʧən",
                "font": "Noto Sans",
                "screenshot": "textbox_exemplar_2.png"
            },
            # The same pangram in Hangul
            {
                "text": "아 프시초피 제알롣 크노W스 아 s믿게 오f wx, 붇 자v앗c립t 잇 테 q왯디온",
                "font": "Noto Sans KR",
                "screenshot": "textbox_exemplar_3.png"
            },
            # A noticeably non-standard font
            {
                "text":
                "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question.",
                "font": "Indie Flower",
                "screenshot": "textbox_exemplar_4.png",
            }
        ]
        # Some text which is likely to cause problems if something isn't working
        tykes = [
            # Text which doesn't render properly on Mac (Issue #3203)
            {
                "text": "कोशिकायें",
                "font": "Noto Sans",
                "screenshot": "textbox_tyke_1.png"
            },
            # Thai text which old Text component couldn't handle due to Pyglet
            {
                "text": "ขาว แดง เขียว เหลือง ชมพู ม่วง เทา",
                "font": "Niramit",
                "screenshot": "textbox_tyke_2.png"
            }
        ]
        # Test each case and compare against screenshot
        for case in exemplars + tykes:
            textbox.reset()
            textbox.fontMGR.addGoogleFont(case['font'])
            textbox.font = case['font']
            textbox.text = case['text']
            self.win.flip()
            textbox.draw()
            if case['screenshot']:
                # Uncomment to save current configuration as desired
                #self.win.getMovieFrame(buffer='back').save(Path(utils.TESTS_DATA_PATH) / case['screenshot'])
                utils.compareScreenshot(Path(utils.TESTS_DATA_PATH) /
                                        case['screenshot'],
                                        self.win,
                                        crit=20)

    def test_basic(self):
        pass

    def test_something(self):
        # to-do: test visual display, char position, etc
        pass
def run():

    from psychopy.visual import Window, TextStim, ImageStim
    from psychopy.core import wait
    from psychopy.event import getKeys, waitKeys, clearEvents
    from numpy.random import shuffle
    from psychopy import gui
    import numpy as np
    import random
    '''
	Next, we want to create the window in which the experiment takes place and open up a log file.
	'''
    #create window
    DISPSIZE = (1000, 700)
    #in case that doesn't work, use DISPSIZE = (1000,700)
    #for windows only DISPSIZE = (GetSystemMetrics(0),GetSystemMetrics(1))
    BGC = 'white'

    #log file
    log = open('logfileprisonersdilemma.txt', 'w')
    log.write('trial round\topponent strategy\participant strategy\n'
              )  #insert headers of what should be logged
    '''
	Now we create the objects we will use. 
	The code here is in the same order as it will be used once we start the game. 
	We'll start with the objects for introduction and instruction.
	
	'''
    win = Window(size=DISPSIZE, units='pix', color=BGC, fullscr=False)
    backgroundimage = ImageStim(win, 'prisonwall.png', size=(1000, 1000))
    #objects for introduction and instruction
    #introduction text
    subject_name = 'Kathi'

    introstr = f'''
	Welcome to the prisoner's dilemma game, {subject_name}!
	This game will take about 10 minutes. 
	Please wait for further instructions after you've finished.
	Press 'space' to continue. 
	'''

    introtxt = TextStim(win,
                        text=introstr,
                        font='Arial',
                        height=30,
                        color='white',
                        wrapWidth=400)

    #instruction text
    inststr = '''
	Imagine you are one of two people being questioned about the same crime. They are each talking to the interrogator separately. The interrogator gives each person the same deal: 
	they can choose to vouch for the other person’s innocence (COOPERATING) or rat them out (DEFECTING). 
	And of course, there’s a twist. If both people cooperate with each other, they’ll each get 3 months off their sentence, 
	but if the first person vouches for the second person, and the second person rats them out, 
	the first person will get no time off their sentence and the second person will get 5 months off their time. 
	Lastly, if they both rat each other out, they each get 1 month off their time.
	
	Press 'space' to start the game.
	'''

    insttxt = TextStim(win,
                       text=inststr,
                       font='Arial',
                       height=25,
                       color='white',
                       wrapWidth=900,
                       pos=(000, -70))
    '''
	Participants as well as their opponent are represented in the game by avatars. These objects are used for explaining this and defining the image objects. 
	These are avatars you can use created with www.hexatar.com, however you are free to use your own. 
	
	This is redunant since I coulnd't figure it out, but I wanted to keep it for the future.
	'''
    #objects for representing participants, images
    #telling people to choose avatar
    avatstr = '''
	Please choose one of these avatars to represent you in the game.
	Just press the key that responds to the letter next to the image.
	'''
    avattxt = TextStim(win,
                       text=avatstr,
                       font='Arial',
                       height=20,
                       color='black',
                       wrapWidth=900,
                       pos=(000, -300))

    #avatars: created with http://www.hexatar.com
    partoverview = ImageStim(
        win, image='partchoice.png', size=(500, 500)
    )  #start screen from which participant chooses an avatar to represent them in the game
    '''
	Here we define objects during the actual game: instructions about controls, a 
	connecting screen, text to be displayed after every round and a goodbye screen.
	'''
    #objects for during the game, in the loop
    sentcountp = 35
    sentcounto = 35

    #info about controls/gameplay, should be displayed on the bottom left during the game
    controlinfo = TextStim(
        win,
        text=
        '''Press the left arrow to defect and the right arrow to cooperate''',
        font='Arial',
        height=20,
        color='white',
        wrapWidth=900,
        pos=(000, -300))

    # txt within game
    connectstr = f'Your prison sentence is {sentcountp} months.\n'
    'Your partner`s sentence is {sentcounto} months.\n'
    'The authorities are still not sure what to do with the two of you. Therefore, you and your partner\n'
    'will be interrogated again by a different police officer. Again you have the choice to cooperate or defect.'

    connecttxt = TextStim(win,
                          text=connectstr,
                          font='Arial',
                          height=20,
                          color='black',
                          wrapWidth=400)
    cooptxt = TextStim(win,
                       text='Your opponent chose to cooperate.',
                       font='Arial',
                       height=20,
                       color='black',
                       wrapWidth=400)
    deftxt = TextStim(win,
                      text='Your opponent chose to defect.',
                      font='Arial',
                      height=20,
                      color='black',
                      wrapWidth=400)

    #goodbye screen
    goodbyestr = ('The game is now over.\n' + 'Thank you for playing!\n')
    goodbye = TextStim(win,
                       text=goodbyestr,
                       font='Arial',
                       height=40,
                       color='black',
                       wrapWidth=500)

    strategy = [1, 2, 3, 4, 5]  #random assignment of opponents strategy
    shuffle(strategy)
    randostrategy = [1, 2]  #for strategy 3
    condlist = [1, 2, 3]  #1 is in-group, 2 is outgroup, 3 is anon
    ntrials = 7
    oppstrategy = '...'  #for updating the sentence counter

    #function that determines participants sentence and adds it to the sentence counter
    #add unitest here
    '''
	During the experiment, we need to update how many months the participant has
	to spend in prison now, depending on the choice they made and the choice their
	opponent made. For doing this during the trial loop, we write the function
	sentencetracker, that checks the participants choice (either cooperating or
	defecting) as well as the opponents strategy and updates the sentence based on this.
	As a reminder: left arrow to defect and the right arrow to cooperate.
	'''
    def sentencetracker(sentcounto, sentcountp, response, oppstrategy):
        if response == 'right' and oppstrategy == 'cooperation':  #both cooperate
            sentcounto -= 3
            sentcountp -= 3
        elif response == 'right' and oppstrategy == 'defect':  #participant wants to cooperate,  but opponent rats them out
            sentcountp -= 5
        elif response == 'left' and oppstrategy == 'cooperation':  #participant rats opponent out, but opponent cooperates
            sentcounto -= 5
        else:  #response == 'left' & oppstrategy == 'defect': #both defect
            sentcountp -= 1
            sentcounto -= 1
        return sentcounto, sentcountp

    '''
	Time to start the experiment!
	Let's start with the introduction. After that, we explain how it works. 
	We also define the image stimuli for displaying the avatars.
	'''
    backgroundimage.draw()  #background prisonwall
    introtxt.draw()
    win.flip()
    waitKeys(keyList=['space'
                      ])  #wait until participant pressed space to continue
    clearEvents()
    ''' that part worked but couldn't figure out avatar assignment :()
	#choosing avatar that represents participant 
	avattxt.draw()
	partoverview.draw()
	win.flip()
	aresponse = waitKeys(keyList = ['a','b','c','d'])
	
	shuffle(condlist) #randomly assigning condition (in group, out group, anonymous opponent)
	#condition = condlist[1]
	'''
    opponent = ImageStim(win, image="opponent1.png", pos=(300, 000))
    participant = ImageStim(win, image='partA.png', pos=(-300, 000))
    ''' was supposed to assign condition and set the right avatars, but doesn't work
	condition = np.random.randint(1,3)
	if condition == 1: #playing with an in-group member
		print('in-group condition')
		if aresponse == 'a': #participant is female caucasian
			opponent = ImageStim(win, image="opponent2.png", pos=(300,000))
			participant = ImageStim(win, image='partA.png', pos=(-300, 000))
		elif aresponse == 'c': #participant is male caucasian 
			opponent = ImageStim(win, image="opponent2.png", pos=(300,000))
			participant = ImageStim(win, image='partC.png', pos=(-300, 000))
		elif aresponse == 'b': #participant is female non-caucasian
			opponent = ImageStim(win, image="opponent1.png", pos=(300,000))
			participant = ImageStim(win, image='partB.png', pos=(-300, 000))
		elif aresponse == 'd': #option d, participant is male non-caucasian
			opponent = ImageStim(win, image="opponent1.png", pos=(300,000))
			participant = ImageStim(win, image='partD.png', pos=(-300, 000))
		
		
		
		
	elif condition == 2: #playing with an out-group member
		print('out-group condition')
		if aresponse == 'a': #participant is female caucasian
			opponent = ImageStim(win, image="opponent1.png", pos=(300,000))
			participant = ImageStim(win, image='partA.png', pos=(-300, 000))
			
		elif aresponse == 'c': #participant is male caucasian 
			opponent = ImageStim(win, image="opponent1.png", pos=(300,000))
			participant = ImageStim(win, image='partC.png', pos=(-300, 000))
			
		elif aresponse == 'b': #participant is female non-caucasian
			opponent = ImageStim(win, image="opponent2.png", pos=(300,000))
			participant = ImageStim(win, image='partB.png', pos=(-300, 000))
			
		elif aresponse == 'd': #option d, participant is male non-caucasian
			opponent = ImageStim(win, image="opponent2.png", pos=(300,000))
			participant = ImageStim(win, image='partD.png', pos=(-300, 000))
			
		
		
	
	elif condition == 3: #playing with no information about opponent
		print('anonymous condition')
		opponent = ImageStim(win, image="anonymous.jpg", pos=(300,000))
		if aresponse == 'a': #participant is female caucasian
			participant = ImageStim(win, image='partA.png', pos=(-300, 000))
			 
		elif aresponse == 'c': #participant is male caucasian 
			participant = ImageStim(win, image='partC.png', pos=(-300, 000))
			
		elif aresponse == 'b': #participant is female non-caucasian
			participant = ImageStim(win, image='partB.png', pos=(-300, 000))
			
		elif aresponse == 'd': #option d, participant is male non-caucasian
			participant = ImageStim(win, image='partD.png', pos=(-300, 000))
			
		
	
	clearEvents()
	'''

    #explaining the game
    backgroundimage.draw()
    insttxt.draw()
    win.flip()
    waitKeys(
        keyList=['space']
    )  #wait until participant read instructions and pressed space to start the trial loop
    strategy = np.random.randint(1, 5)
    '''
	Sentence count for the participant and the opponent. You can change this according to your needs, 
	however please note that it's 35 because we defined 7 trial rounds and the maximum the 
	sentence can change during each round is 5. 7 x 5 is 35, so this is set to prevent the sentence count
	from going below 0.
	'''
    sentcounto = 35
    sentcountp = 35
    '''
	This is the trial loop, it's now set to 7 rounds (see object ntrials = 7 above to change it).
	Opponents stick to the same strategy through all 7 rounds. 
	Sentence count as well as strategies are printed in the console as well as logged in the log file.
	'''

    i = 0
    for i in range(ntrials):
        backgroundimage.draw()
        i += 1
        log.write(str(i))
        log.write('\t')

        #opponent always cooperates
        if strategy == 1:
            opponent.draw()
            participant.draw()
            controlinfo.draw()
            win.flip()
            log.write('strategy cooperation\t')
            response = waitKeys(keyList=['left', 'right'])
            if response == 'left':
                log.write('defect\n')
            elif response == 'right':
                log.write('cooperate\n')
            cooptxt.draw()
            win.flip()
            wait(4)  #seconds
            oppstrategy = 'cooperation'
            print('strategy cooperation')
            sentcounto, sentcountp = sentencetracker(sentcounto, sentcountp,
                                                     response, oppstrategy)
            print(sentcounto, sentcountp)
            connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
            connecttxt = TextStim(win,
                                  text=connectstr,
                                  font='Arial',
                                  height=20,
                                  color='black',
                                  wrapWidth=400)
            connecttxt.draw()
            win.flip()
            wait(7)

        #opponent always defects
        elif strategy == 2:
            opponent.draw()
            participant.draw()
            controlinfo.draw()
            win.flip()
            log.write('strategy defect\t')
            response = waitKeys(keyList=['left', 'right'])
            if response == 'left':
                log.write('defect\n')
            elif response == 'right':
                log.write('cooperate\n')
            deftxt.draw()
            win.flip()
            wait(4)  #seconds
            oppstrategy = 'defect'
            print('strategy defect')
            sentcounto, sentcountp = sentencetracker(sentcounto, sentcountp,
                                                     response, oppstrategy)
            print(sentcounto, sentcountp)
            connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
            connecttxt = TextStim(win,
                                  text=connectstr,
                                  font='Arial',
                                  height=20,
                                  color='black',
                                  wrapWidth=400)
            connecttxt.draw()
            win.flip()
            wait(7)

        #opponent cooperates or defects on a random basis
        elif strategy == 3:
            rando = np.random.randint(1, 3)
            print('rando')
            if rando == 1:
                opponent.draw()
                participant.draw()
                controlinfo.draw()
                win.flip()
                log.write('strategy random cooperation\t')
                response = waitKeys(keyList=['left', 'right'])
                if response == 'left':
                    log.write('defect\n')
                elif response == 'right':
                    log.write('cooperate\n')
                cooptxt.draw()
                win.flip()
                wait(4)
                oppstrategy = 'cooperation'
                print('rando coop')
                sentcounto, sentcountp = sentencetracker(
                    sentcounto, sentcountp, response, oppstrategy)
                print(sentcounto, sentcountp)
                connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
                connecttxt = TextStim(win,
                                      text=connectstr,
                                      font='Arial',
                                      height=20,
                                      color='black',
                                      wrapWidth=400)
                connecttxt.draw()
                win.flip()
                wait(7)
            else:
                opponent.draw()
                participant.draw()
                controlinfo.draw()
                win.flip()
                log.write('strategy random defect\t')
                wait(4)
                response = waitKeys(keyList=['left', 'right'])
                if response == 'left':
                    log.write('defect\n')
                elif response == 'right':
                    log.write('cooperate\n')
                deftxt.draw()
                win.flip()
                wait(4)  #seconds
                oppstrategy = 'defect'
                print('rando defect')
                sentcounto, sentcountp = sentencetracker(
                    sentcounto, sentcountp, response, oppstrategy)
                print(sentcounto, sentcountp)
                connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
                connecttxt = TextStim(win,
                                      text=connectstr,
                                      font='Arial',
                                      height=20,
                                      color='black',
                                      wrapWidth=400)
                connecttxt.draw()
                win.flip()
                wait(7)

        elif strategy == 4:
            print('nice tit for tat')
            log.write('strategy nice tit for tat\t')
            if i == 1:
                opponent.draw()
                participant.draw()
                controlinfo.draw()
                win.flip()
                response = waitKeys(keyList=['left', 'right'])
                if response == 'left':
                    log.write('defect\n')
                elif response == 'right':
                    log.write('cooperate\n')
                cooptxt.draw()
                win.flip()
                wait(4)
                oppstrategy = 'cooperation'
                print('cooperation')
                sentcounto, sentcountp = sentencetracker(
                    sentcounto, sentcountp, response, oppstrategy)
                print(sentcounto, sentcountp)
                connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
                connecttxt = TextStim(win,
                                      text=connectstr,
                                      font='Arial',
                                      height=20,
                                      color='black',
                                      wrapWidth=400)
                connecttxt.draw()
                win.flip()
                wait(7)  #seconds

            elif i > 1:
                if response == 'right':
                    opponent.draw()
                    participant.draw()
                    controlinfo.draw()
                    win.flip()
                    response = waitKeys(keyList=['left', 'right'])
                    if response == 'left':
                        log.write('defect\n')
                    elif response == 'right':
                        log.write('cooperate\n')
                    cooptxt.draw()
                    win.flip()
                    wait(4)
                    oppstrategy = 'cooperation'
                    print('cooperation')
                    sentcounto, sentcountp = sentencetracker(
                        sentcounto, sentcountp, response, oppstrategy)
                    print(sentcounto, sentcountp)
                    connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
                    connecttxt = TextStim(win,
                                          text=connectstr,
                                          font='Arial',
                                          height=20,
                                          color='black',
                                          wrapWidth=400)
                    connecttxt.draw()
                    win.flip()
                    wait(7)  #seconds

                elif response == 'left':
                    opponent.draw()
                    participant.draw()
                    controlinfo.draw()
                    win.flip()
                    response = waitKeys(keyList=['left', 'right'])
                    if response == 'left':
                        log.write('defect\n')
                    elif response == 'right':
                        log.write('cooperate\n')
                    deftxt.draw()
                    win.flip()
                    wait(4)
                    oppstrategy = 'defect'
                    print('defect')
                    sentcounto, sentcountp = sentencetracker(
                        sentcounto, sentcountp, response, oppstrategy)
                    print(sentcounto, sentcountp)
                    connectstr = f'''Your prison sentence is {sentcountp} months.
	Your partner`s sentence is {sentcounto} months.
	The authorities are still not sure what to do with the two of you. 
	Therefore, you and your partner will be interrogated again by a different police officer. 
	Again you have the choice to cooperate or defect.'''
                    connecttxt = TextStim(win,
                                          text=connectstr,
                                          font='Arial',
                                          height=20,
                                          color='black',
                                          wrapWidth=400)
                    connecttxt.draw()
                    win.flip()
                    wait(7)  #seconds

        elif strategy == 5:
            print('suspicious tit for tat')
            log.write('strategy suspicious tit for tat\t')
            if i == 1:
                opponent.draw()
                participant.draw()
                controlinfo.draw()
                win.flip()
                response = waitKeys(keyList=['left', 'right'])
                if response == 'left':
                    log.write('defect\n')
                elif response == 'right':
                    log.write('cooperate\n')
                deftxt.draw()
                win.flip()
                wait(4)
                oppstrategy = 'defect'
                print('defect')
                sentcounto, sentcountp = sentencetracker(
                    sentcounto, sentcountp, response, oppstrategy)
                print(sentcounto, sentcountp)
                connectstr = f'''Your prison sentence is {sentcountp} months.
		Your partner`s sentence is {sentcounto} months.
		The authorities are still not sure what to do with the two of you. 
		Therefore, you and your partner will be interrogated again by a different police officer. 
		Again you have the choice to cooperate or defect.'''
                connecttxt = TextStim(win,
                                      text=connectstr,
                                      font='Arial',
                                      height=20,
                                      color='black',
                                      wrapWidth=400)
                connecttxt.draw()
                win.flip()
                wait(7)  #seconds

            elif i > 1:
                if response == 'right':
                    opponent.draw()
                    participant.draw()
                    controlinfo.draw()
                    win.flip()
                    response = waitKeys(keyList=['left', 'right'])
                    if response == 'left':
                        log.write('defect\n')
                    elif response == 'right':
                        log.write('cooperate\n')
                    cooptxt.draw()
                    win.flip()
                    wait(4)
                    oppstrategy = 'cooperation'
                    print('cooperation')
                    sentcounto, sentcountp = sentencetracker(
                        sentcounto, sentcountp, response, oppstrategy)
                    print(sentcounto, sentcountp)
                    connectstr = f'''Your prison sentence is {sentcountp} months.
		Your partner`s sentence is {sentcounto} months.
		The authorities are still not sure what to do with the two of you. 
		Therefore, you and your partner will be interrogated again by a different police officer. 
		Again you have the choice to cooperate or defect.'''
                    connecttxt = TextStim(win,
                                          text=connectstr,
                                          font='Arial',
                                          height=20,
                                          color='black',
                                          wrapWidth=400)
                    connecttxt.draw()
                    win.flip()
                    wait(7)  #seconds

                elif response == 'left':
                    opponent.draw()
                    participant.draw()
                    controlinfo.draw()
                    win.flip()
                    response = waitKeys(keyList=['left', 'right'])
                    if response == 'left':
                        log.write('defect\n')
                    elif response == 'right':
                        log.write('cooperate\n')
                    deftxt.draw()
                    win.flip()
                    wait(4)
                    oppstrategy = 'defect'
                    print('defect')
                    sentcounto, sentcountp = sentencetracker(
                        sentcounto, sentcountp, response, oppstrategy)
                    print(sentcounto, sentcountp)
                    connectstr = f'''Your prison sentence is {sentcountp} months.
		Your partner`s sentence is {sentcounto} months.
		The authorities are still not sure what to do with the two of you. 
		Therefore, you and your partner will be interrogated again by a different police officer. 
		Again you have the choice to cooperate or defect.'''
                    connecttxt = TextStim(win,
                                          text=connectstr,
                                          font='Arial',
                                          height=20,
                                          color='black',
                                          wrapWidth=400)
                    connecttxt.draw()
                    win.flip()
                    wait(7)  #seconds

        #exit early:
        quitt = getKeys(keyList='q')
        if len(quitt) > 0:
            break

    goodbye.draw()
    win.flip()
    wait(3)

    win.close()
    log.close()
예제 #30
0
class Experiment:
    """
    Base experiment class
    """

    def __init__(self, exp_info, file_name):
        """
        Initialize experiment - read XML file, setup window, connect to netstation and tobii
        exp_info - experiment information
        file_name - name of XML file containing experiment definition
        """
        self.exp_info = exp_info
        self.name = None
        self.type = None
        self.num_blocks = 0
        self.blocks = {}
        self.block_order = []

        # Window to use
        wintype = 'pyglet'  # use pyglet if possible, it's faster at event handling
        # Add 14cm to distance - this is distance from eyetracker to monitor
        mon = monitors.Monitor(exp_info['monitor'], distance=float(exp_info['monitor distance']))
        self.win = Window(
            [1280, 1024],
            monitor=mon,
            screen=SCREEN,
            units="deg",
            fullscr=True,
            #fullscr=False,
            color=[-1, -1, -1],
            winType=wintype)
        self.win.setMouseVisible(False)
        event.clearEvents()

        # Measure frame rate
        self.mean_ms_per_frame, std_ms_per_frame, median_ms_per_frame = visual.getMsPerFrame(self.win, nFrames=60,
                                                                                             showVisual=True)

        self.debug_sq=None
        if exp_info['monitor']=='tobii':
            self.debug_sq=psychopy.visual.Rect(self.win, width=30, height=30, units='pix')
            self.debug_sq.setFillColor((1,1,1))
            self.debug_sq.setPos((630,-500))

        # Compute distractor duration in frames based on frame rate
        distractor_duration_frames = int(2000.0/self.mean_ms_per_frame)

        # Initialize set of distractors
        self.distractor_set = DistractorSet(os.path.join(DATA_DIR, 'images', 'distractors', 'space'),
                                            os.path.join(DATA_DIR, 'sounds', 'distractors'),
                                            os.path.join(DATA_DIR, 'movies', 'distractors'),
                                            os.path.join(DATA_DIR, 'images', 'distractors', 'star-cartoon.jpg'),
                                            distractor_duration_frames, self.win)

        # Connect to nestation
        self.ns = None
        if exp_info['eeg']:
            # connect to netstation
            self.ns = egi.Netstation()
            ms_localtime = egi.ms_localtime

        self.eye_tracker = None
        mouse_visible = False
        if exp_info['eyetracking source'] == 'tobii':
            # Initialize eyetracker
            self.eye_tracker = TobiiController(self.win)
            self.eye_tracker.waitForFindEyeTracker()
            self.eye_tracker.activate(EYETRACKER_NAME)
        elif exp_info['eyetracking source'] == 'mouse':
            mouse_visible = True

        # Initialize mouse
        self.mouse = event.Mouse(visible=mouse_visible, win=self.win)

        self.gaze_debug=None
        if self.exp_info['debug mode']:
            self.gaze_debug=psychopy.visual.Circle(self.win, radius=1, fillColor=(1.0,-1.0,-1.0))

        self.read_xml(file_name)

        # Initialize netstation and eyetracker
        self.initialize()

    def calibrate_eyetracker(self):
        """
        Run eyetracker calibration routine
        """
        retval = 'retry'
        while retval == 'retry':
            waitkey = True
            retval = None
            can_accept = self.eye_tracker.doCalibration(EYETRACKER_CALIBRATION_POINTS)
            while waitkey:
                for key in psychopy.event.getKeys():
                    if can_accept:
                        num_entered=True
                        try:
                            calib_idx=int(key)
                            can_accept = self.eye_tracker.doCalibration([EYETRACKER_CALIBRATION_POINTS[calib_idx-1]],
                                                                        calib=self.eye_tracker.calib)
                        except:
                            num_entered=False
                        if not num_entered and key == 'a':
                            retval = 'accept'
                            waitkey = False
                    elif key == 'r':
                        retval = 'retry'
                        waitkey = False
                    elif key == 'escape':
                        retval = 'abort'
                        waitkey = False
                self.eye_tracker.calresult.draw()
                self.eye_tracker.calresultmsg.draw()
                for point_label in self.eye_tracker.point_labels:
                    point_label.draw()
                self.win.flip()

        if retval == 'abort':
            self.eye_tracker.closeDataFile()
            self.eye_tracker.destroy()
            self.win.close()
            core.quit()

    def initialize(self):
        """
        Start netstation recording, calibrate eyetracker
        """
        if self.ns is not None:
            try:
                self.ns.initialize(NETSTATION_IP, 55513)
                self.ns.BeginSession()
                self.ns.StartRecording()
            except:
                print('Could not connect with NetStation!')

        # Initialize logging
        logfile = os.path.join(DATA_DIR, 'logs', self.exp_info['experiment'], '%s_%s_%s.log' % (self.exp_info['child_id'],
                                                                                                self.exp_info['date'],
                                                                                                self.exp_info['session']))

        if self.eye_tracker is not None:
            self.eye_tracker.setDataFile(logfile, self.exp_info)
        else:
            datafile = open(logfile, 'w')
            datafile.write('Recording date:\t' + datetime.datetime.now().strftime('%Y/%m/%d') + '\n')
            datafile.write('Recording time:\t' + datetime.datetime.now().strftime('%H:%M:%S') + '\n')
            datafile.write('Recording resolution\t%d x %d\n' % tuple(self.win.size))
            for key, data in self.exp_info.iteritems():
                datafile.write('%s:\t%s\n' % (key, data))
            datafile.close()

        # Create random block order
        n_repeats = int(self.num_blocks/len(self.blocks.keys()))
        for i in range(n_repeats):
            subblock_order = copy.copy(self.blocks.keys())
            np.random.shuffle(subblock_order)
            self.block_order.extend(subblock_order)

        # Synch with netstation in between trials
        if self.ns is not None:
            self.ns.sync()

        if self.eye_tracker is not None:
            self.eye_tracker.startTracking()

    def close(self):
        """
        Disconnect from eyetracker and netstation
        """
        if self.eye_tracker is not None:
            self.eye_tracker.stopTracking()
            self.eye_tracker.closeDataFile()

        # close netstation connection
        if self.ns:
            self.ns.StopRecording()
            self.ns.EndSession()
            self.ns.finalize()

        self.win.close()
        core.quit()
        if self.eye_tracker is not None:
            self.eye_tracker.destroy()

    def run(self):
        """
        Run task
        ns - netstation connection
        """
        pass

    def read_xml(self, file_name):
        """
        Read experiment definition file
        :param file_name: file to read definition from
        """
        pass
예제 #31
0
print('Max. flow rate: .3%f %s' % (pump.maxFlowRate, pump.flowRateUnit))

win = Window()
msg = ('Press one of the following keys: \n\n'
       '    F – Fill Syringe at 1 mL/s\n'
       '    E – Empty Syringe at 1 mL/s\n'
       '    A – Aspirate 1 mL at 1 mL/s\n'
       '    D – Dispense 1 mL at 1 mL/s\n'
       '\n'
       '    Q – Quit')
t = TextStim(win, msg)

event.clearEvents()
while True:
    t.draw()
    win.flip()

    # Retrieve keypresses. The user can completely fill or empty the syringe,
    # or aspirate or dispense a small volume (1 mL) by pressing the
    # corresponding keys.
    #
    # When aspirating or dispensing, the code halts further script execution
    # until the pump operation has finished, and then immediately switches the
    # valve position (i.e., from inlet to outlet after aspiration, and from
    # outlet to inlet after dispense). During an experiment, this can ensure
    # a sharp(er) stimulus offset.

    keys = event.getKeys(keyList=['f', 'e', 'a', 'd', 'q'])
    if 'f' in keys:
        pump.fill(flowRate=1, waitUntilDone=False)
    elif 'e' in keys:
예제 #32
0
class MDTO(object):
    def __init__(self, logfile, imgDir, screenType, expVariant, trialDuration,
                 ISI, trialsPer, selfPaced, practiceTrials, inputButtons,
                 pauseButton):

        self.logfile = logfile
        self.expVariant = expVariant
        self.trialDuration = trialDuration
        self.selfPaced = selfPaced
        self.ISI = ISI
        self.trialsPer = trialsPer
        self.imgDir = imgDir
        self.leftOvers = []
        self.splitLures = self.SplitLures()
        self.splitSingles = self.SplitSingles()
        self.runPracticeTrials = practiceTrials
        self.leftButton = inputButtons[0]
        self.rightButton = inputButtons[1]
        self.pauseButton = pauseButton

        if (screenType == 'Windowed'):
            screenSelect = False
        elif (screenType == 'Fullscreen'):
            screenSelect = True

        self.window = Window(fullscr=screenSelect,
                             units='pix',
                             color='White',
                             allowGUI=False)
        self.imageWidth = self.window.size[1] / 3

        #Define the black box that appears in the lower left, to signal EEG
        rW = 110  #Width
        rH = 60  #Height
        rectVertices = [[rW, -rH], [-rW, -rH], [-rW, rH], [rW, rH]]
        rectCenter = [(-self.window.size[0] / 2 + rW),
                      (-self.window.size[1] / 2) + rH]
        self.blackBox = ShapeStim(self.window,
                                  fillColor='black',
                                  units='pix',
                                  fillColorSpace='rgb',
                                  vertices=rectVertices,
                                  closeShape=True,
                                  interpolate=True,
                                  pos=rectCenter)
        self.rangeITI = numpy.arange(1, 1.4, .001)

        self.clock = Clock()

        #Initialize scorelist for 4 categories|| [correct,incorrect,response]
        self.scoreList = []
        for i in range(0, 4):
            self.scoreList.append([0, 0, 0])

    def GrabFileType(self, fileList, exts):
        """Takes an inputted list, as well as extension, and returns a list with
        the elements in the original list that have the desired extension.

        fileList: The list of files to search through
        ext: string containing the extension type, e.g. ".jpg", ".png"

        return: a new list, containing files only of ext type
        """
        fileListofType = []

        for aFile in fileList:
            for ext in exts:
                ftLen = len(ext)
                if (aFile[-ftLen:] == ext):
                    fileListofType.append(aFile)
                    break

        return fileListofType

    def SplitLures(self):
        """Creates and returns a list of image lures. Lures are taken from
        both the lure high and lure low directory, and an equal amount of 
        each are put into the list. Each element in the returned list has 2
        elements: [imgA,imgB] and a number, pertaining to the difficulty of
        the lure, i.e. the  degree of apparent difference between the two images.

        Return: a list, each element being: [[imgA,imgB], lureNum]
        """
        dirFiles = os.listdir(self.imgDir)
        imgTypes = ['.jpg', '.jpeg', '.JPG']
        allImgs = self.GrabFileType(dirFiles, imgTypes)
        allImgs = [img for img in allImgs if "PR" not in img]
        lureLowImgs = []
        lureHighImgs = []
        for img in allImgs:
            if (img[5] == "1"):
                lureHighImgs.append(img)
            elif (img[5] == "2"):
                lureLowImgs.append(img)

        #Sort images by name
        lureHighImgs.sort()
        lureLowImgs.sort()

        #Return a list of lures as a list w/: [[imgA,imgB],lureType]
        def LureListGroup(imgList):
            lureList = []
            for i in range(0, int(len(imgList) / 2)):
                imgA = imgList[i * 2]
                imgB = imgList[(i * 2) + 1]
                highSet = [imgA, imgB]
                lureList.append(highSet)
            return lureList

        #Create list of lures with embedded structure, then shuffle
        lureHighList = LureListGroup(lureHighImgs)
        lureLowList = LureListGroup(lureLowImgs)
        random.shuffle(lureHighList)
        random.shuffle(lureLowList)

        #Put number (num of trials) of list items from both lists into list
        selectedList = []
        for i in range(0, self.trialsPer):
            selectedList.append(lureHighList[i])
            selectedList.append(lureLowList[i])

        #Unused "leftover" A images will be used as singles
        #Probably want to use other method while seeded rand unimplemented
        #OK for now
        for i in range(self.trialsPer + 1, len(lureHighList)):
            try:
                self.leftOvers.append(lureHighList[i][0])
            except IndexError:
                pass
            try:
                self.leftOvers.append(lureLowList[i][0])
            except IndexError:
                pass

        random.shuffle(selectedList)
        return selectedList

    def SplitSingles(self):
        """Creates and returns a list of image "singles". Each item in the
        list is an image, followed by either "sF" (single Foil) or "sR"
        (single repeat), indicating if it is to be shown once or twice.

        return: list composed of [imageFileName, type]
                type: "sR" or "sF"
        """
        singles = self.leftOvers
        targetsFoils = []
        for i in range(0, self.trialsPer * 2):
            if (i % 2 == 0):
                targetsFoils.append([singles[i], "sR"])
            else:
                targetsFoils.append([singles[i], "sF"])

        random.shuffle(targetsFoils)
        return targetsFoils

    def Pause(self):
        """Pauses the task, and displays a message waiting for a spacebar
        input from the user before continuing to proceed.
        """
        pauseMsg = "Experiment Paused\n\nPress '{}' to continue".format(
            self.pauseButton)
        pauseText = TextStim(self.window,
                             text=pauseMsg,
                             color='Black',
                             height=40)
        pauseText.draw(self.window)
        self.window.flip()
        waitKeys(keyList=[self.pauseButton])
        clearEvents()

    def ScaleImage(self, image, maxSize=350):
        """Scales the size of the image to fit as largely as it can within the 
        window of the defined maxSize, while preserving its aspect ratio.

        image: the filename of the image to be scaled
        maxSize: maximum size, in pixels of image
        return: maximum scaling of image
        """
        im = Image.open(image)
        larger = im.size[0]
        if (im.size[0] < im.size[1]):
            larger = im.size[1]
        scale = larger / maxSize
        scaledSize = (im.size[0] / scale, im.size[1] / scale)
        return scaledSize

    def RunTrialECog(self, image, phase):
        """Runs a particular trial for an ECog (Electrocorticography) based 
        task. An ECog trial runs as follows: display the image along with
        the black box for <trial duration> amount of time, clear the screen
        for <ISI> amount of time, then asking for and getting subject input
        for <ITI> amount of time.

        image: the stimuli to display on screen
        phase: 0 (Study Phase) - prompts user "Indoor / Outdoor"
               1 (Test Phase) - prompts user "Old / New"
        return: [keyPress, reactionTime]
        """
        theImage = ImageStim(self.window)
        #Set the full path of the image, based on the image's lure type
        if (image[0][5] == "3"):
            image = (self.imgSnglDir + '%s' % (image[0]))
        elif ((image[0][5] == "1") or (image[0][5] == "2")):
            image = (self.lureHighDir + '%s' % (image[0]))
        elif ((image[0][5] == "4") or (image[0][5] == "5")):
            image = (self.lureLowDir + '%s' % (image[0]))

        theImage.setImage(image)
        imageSize = self.ScaleImage(image, self.imageWidth)
        theImage.setSize(imageSize)

        ecogISI = 0.5
        posLeftText = (-(self.window.size[0] / 8), 0)
        posRightText = ((self.window.size[0] / 8), 0)
        if (phase == 0):
            ecogTrialDur = 2.0
            leftMsg = "Indoor\n\n    1"
            rightMsg = "Outdoor\n\n     2"
        else:
            ecogTrialDur = 1.0
            leftMsg = "Old\n\n  1"
            rightMsg = "New\n\n  2"

        theImage.draw(self.window)
        self.blackBox.draw(self.window)
        self.window.flip()
        wait(ecogTrialDur, ecogTrialDur)
        self.window.flip()
        wait(ecogISI, ecogISI)
        textLeft = TextStim(self.window,
                            text=leftMsg,
                            pos=posLeftText,
                            color='Black',
                            height=50)
        textRight = TextStim(self.window,
                             text=rightMsg,
                             pos=posRightText,
                             color='Black',
                             height=50)
        textLeft.draw(self.window)
        textRight.draw(self.window)
        self.window.flip()
        clearEvents()
        self.clock.reset()
        keyPresses = waitKeys(keyList=['1', '2', 'space', 'escape'],
                              timeStamped=self.clock,
                              maxWait=1.5)
        self.window.flip()
        random.shuffle(self.rangeITI)
        wait(self.rangeITI[0], self.rangeITI[0])

        if (not keyPresses):
            return '', 0
        return keyPresses[0][0], keyPresses[0][1]

    def RunTrial(self, image):
        """Runs a particular trial, which includes displaying the image to the
        screen, and gathering the keypresses and their respective response times. 

        image: the image (filename) to display
        returns: [keyPress, reaction time]
        """
        theImage = ImageStim(self.window)
        imagePath = os.path.normpath(self.imgDir + "/%s" % (image))

        theImage.setImage(imagePath)
        imageSize = self.ScaleImage(imagePath, self.imageWidth)
        theImage.setSize(imageSize)
        theImage.draw(self.window)
        self.window.flip()
        clearEvents()
        self.clock.reset()
        keyPresses = []
        if (self.selfPaced == False):
            wait(self.trialDuration, self.trialDuration)
            keyPresses = getKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, 'escape'
            ],
                                 timeStamped=self.clock)
        elif (self.selfPaced == True):
            keyPresses = waitKeys(keyList=[
                self.leftButton, self.rightButton, self.pauseButton, 'escape'
            ],
                                  timeStamped=self.clock)
        self.window.flip()
        wait(self.ISI)
        if (not keyPresses):
            return '', 0
        return keyPresses[0][0], keyPresses[0][1]

    def RunStudy(self):
        """Runs the first part of the MDT-O experiment, or the Study phase.
        In this phase, all target versions of the image pairs are shown, as
        well as half of the "singles" images. Keypresses and their repsective
        reaction times are recorded during this period, and no "right or
        wrong" answers are graded.
        """
        ecog = False if self.expVariant != "ECog" else True
        studyPromptN = (
            "Let's do the real test. \n\n Are the following objects indoor or outdoor? \n\n Press 'p' to continue"
        )
        '''
        studyPromptE = ("In the following phase, a sequence of images will be "
                        "shown.\n\n-Press '1' if the image is of an indoor "
                        "object.\n\n-Press '2' if the image is of an outdoor "
                        "object.\n\n\nPress space to begin"
                       )
        '''
        studyText = TextStim(self.window, studyPromptN, color='Black')
        if ecog:
            studyText = TextStim(self.window, studyPromptE, color='Black')
        studyText.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=[self.pauseButton, 'escape'])
        if (continueKey[0] == 'escape'):
            self.logfile.write("\n\n\nStudy Not Run\n\n")
            return 0

        self.logfile.write("\nBegin Study\n\n")
        logStudyFormat = '{:<7}{:<12s} {:<10s} {:<10s} {:<4s}\n'.format(
            'Trial', 'Image', 'ImageType', 'Response', 'RT')
        self.logfile.write(logStudyFormat)

        #Create list for study: "A" pairs (targets), and repeat singles
        studyImgList = []
        for pair in self.splitLures:
            studyImgList.append([pair[0], pair[0][5]])
        for img in self.splitSingles:
            if (img[1] == "sR"):
                studyImgList.append(img)

        #Shuffle study list
        random.shuffle(studyImgList)

        #Run trial for each study image
        for i in range(0, len(studyImgList)):
            if not ecog:
                (response, RT) = self.RunTrial(studyImgList[i][0])
            else:
                (response, RT) = self.RunTrialECog(studyImgList[i][0], 0)
            if (response == "escape"):
                self.logfile.write("\n\nStudy terminated early\n\n")
                return 0
            elif (response == self.pauseButton):
                self.Pause()

            trialFormat = '{:<7}{:<17s}{:<10s}{:<6s}{:<4.3f}\n'.format(
                i + 1, studyImgList[i][0], studyImgList[i][1], response, RT)
            self.logfile.write(trialFormat)

        return 1

    def RunTest(self):
        """Runs the second part of the MDT-O experiment, or the Test phase.
        In this phase, high and low "lures" are shown, as well as all of the
        "singles" shown in the study phase, as well as entirely new images
        known as "foils".

        All keypresses and their respective reaction times are recorded during
        this period. Additionally, a tally is kept of whether the subjects
        answer was wrong or right, with a separate score for "pair" answers.
        """
        ecog = False if self.expVariant != "ECog" else True
        testPromptN = (
            "In this phase, another sequence of images will be shown"
            "\n\nAre the objects old or new?\n\n Press 'p' to continue.")
        '''testPromptE = ("In this phase, another sequence of images will be shown."
                      "\n\n-Press '1' if the image presented was also shown "
                      "in the previous phase. (Old Image)\n\n-Press '2' if the" 
                      "image presented was not shown in the previous phase."
                      " (New Image)\n\n\nPress space to begin"
                      )
        '''
        testText = TextStim(self.window, text=testPromptN, color='Black')
        if ecog:
            testText = TextStim(self.window, text=testPromptE, color='Black')

        testText.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=[self.pauseButton, 'escape'])
        if (continueKey[0] == 'escape'):
            self.logfile.write("\n\n\nTest Not Run\n\n")
            return 0

        self.logfile.write("\nBegin Test\n\n")
        logTestFormat = '{:<7}{:<12}{:<11}{:<9}{:<10}{:<4}\n'.format(
            'Trial', 'Image', 'ImageType', 'CorResp', 'Response', 'RT')
        self.logfile.write(logTestFormat)

        #Create trial list for test: B and C lures, and all singles
        testImgList = []
        for pair in self.splitLures:
            testImgList.append([pair[1], pair[1][5]])
        for img in self.splitSingles:
            testImgList.append(img)

        #Shuffle trial list
        random.shuffle(testImgList)

        #Run trial for each image in list, get responses
        for i in range(0, len(testImgList)):

            correct = self.rightButton
            trialType = testImgList[i][1]
            if (trialType == "sR"):
                correct = self.leftButton
            if not ecog:
                (response, RT) = self.RunTrial(testImgList[i][0])
            else:
                (response, RT) = self.RunTrialECog(testImgList[i][0], 1)
            if (response == "escape"):
                self.logfile.write("\n\nTest terminated early\n\n")
                break
            elif (response == self.pauseButton):
                self.Pause()

            trialFormat = '{:<7}{:<15}{:<11}{:<9}{:<6}{:<4.3f}\n'.format(
                i + 1, testImgList[i][0], testImgList[i][1], correct, response,
                RT)
            self.logfile.write(trialFormat)

            #Tally scores of correct/responses
            if (response):
                if (trialType == "sR"):
                    self.scoreList[0][2] += 1
                    if (response == correct):
                        self.scoreList[0][0] += 1
                    else:
                        self.scoreList[0][1] += 1
                elif (trialType == "1"):
                    self.scoreList[1][2] += 1
                    if (response == correct):
                        self.scoreList[1][0] += 1
                    else:
                        self.scoreList[1][1] += 1
                elif (trialType == "2"):
                    self.scoreList[2][2] += 1
                    if (response == correct):
                        self.scoreList[2][0] += 1
                    else:
                        self.scoreList[2][1] += 1
                elif (trialType == "sF"):
                    self.scoreList[3][2] += 1
                    if (response == correct):
                        self.scoreList[3][0] += 1
                    else:
                        self.scoreList[3][1] += 1

        return 1

    def ShowPromptAndWaitForSpace(self, prompt, keylist=['p', 'escape']):
        '''
        Show the prompt on the screen and wait for space, or the keylist specified
        returns the key pressed
        '''
        keylist = [self.pauseButton, 'escape']
        text = TextStim(self.window, prompt, color='Black')
        text.draw(self.window)
        self.window.flip()
        continueKey = waitKeys(keyList=keylist)
        if len(continueKey) != 0 and continueKey[0] == 'escape':
            self.logfile.write("Terminated early.")
            self.logfile.close()
            sys.exit()
        return continueKey

    def RunSinglePractice(self, practiceBlock, images):
        '''
        Read in the images we want, and run the practice block for this subject
        
        Run encoding and test, and write to the logs 
        
        Return:
           float: ratio correct
        '''
        imgPairs = []
        for i in range(0, len(images) - 1, 2):
            if "foil" in images[i]:
                t = "sF"
            elif "target" in images[i]:
                t = "sR"
            elif "high" in images[i]:
                t = "2"
            elif "low" in images[i]:
                t = "1"
            imgPairs.append([images[i], images[i + 1], t])

        ### Encoding
        self.ShowPromptAndWaitForSpace(
            " Outdoor or Indoor? ('{}' to continue)".format(self.pauseButton))
        random.shuffle(imgPairs)

        self.logfile.write(
            "\nBegin Practice Encoding {}\n\n".format(practiceBlock))
        logPracticeFormat = '{:<7}{:<17}{:<11}{:<9}{:<10}{:<4}\n'.format(
            'Trial', 'Image', 'ImageType', 'CorResp', 'Response', 'RT')
        self.logfile.write(logPracticeFormat)

        # Run the trial for each encoding trial
        for i, trial in enumerate(imgPairs):
            imgA, imgB, trialType = trial
            if trialType != 'sF':
                response, RT = self.RunTrial(imgA)

                if (response == 'escape'):
                    self.logfile.write(
                        "\n\nPractice block terminated early\n\n")
                    self.logfile.close()
                    sys.exit()
                elif (response == self.pauseButton):
                    self.Pause()

                trialFormat = '{:<7}{:<17}{:<11}{:<9}{:<6}{:<4.3f}\n'.format(
                    i + 1, imgA, trialType, '', response, RT)
                self.logfile.write(trialFormat)

        ### Test
        self.ShowPromptAndWaitForSpace(
            " Old or new? ('{}' to continue)".format(self.pauseButton))
        random.shuffle(imgPairs)

        self.logfile.write(
            "\nBegin Practice Test {}\n\n".format(practiceBlock))
        self.logfile.write(logPracticeFormat)

        # Keep track of the total number they got correct
        totalCorrect = 0
        for i, trial in enumerate(imgPairs):
            imgA, imgB, trialType = trial
            if trialType == 'sR' or trialType == 'sF':
                response, RT = self.RunTrial(imgA)
            else:
                response, RT = self.RunTrial(imgB)

            correct = self.leftButton if trialType == 'sR' else self.rightButton
            if response == correct:
                totalCorrect += 1
            if (response == "escape"):
                self.logfile.write("\n\nPractice terminated early\n\n")
                return -1
            elif (response == self.pauseButton):
                self.Pause()

            trialFormat = '{:<7}{:<17}{:<11}{:<9}{:<6}{:<4.3f}\n'.format(
                i + 1, imgA, trialType, correct, response, RT)
            self.logfile.write(trialFormat)

        # Return the percentage correct
        return totalCorrect / len(imgPairs)

    def RunPractice(self):
        '''
        Runs three rounds of practice trials. 
        If the participant gets a certain amount correct, they move on to the real test.
        '''

        dirFiles = os.listdir(self.imgDir)
        practiceImages = [img for img in dirFiles if "PR" in img]

        # Run each practice session
        for i in range(3):
            practicePrompt = "Let's practice. ('{}' to continue)".format(
                self.pauseButton)
            self.ShowPromptAndWaitForSpace(practicePrompt)

            imagesThisPracticeSession = sorted([
                img for img in practiceImages if "Set_{}".format(i + 1) in img
            ])
            results = self.RunSinglePractice(i + 1, imagesThisPracticeSession)

            # If they get a certain percentage correct, then stop the practice
            self.ShowPromptAndWaitForSpace(
                "You got {}% correct! ('{}' to continue)".format(
                    int(results * 100), self.pauseButton))
            if results > .6:
                return

    def RunExp(self):
        """Run through an instance of the task, which includes the study and test
        phases. Also prints the exit message at the end, and closes the logfile
        if scores are not being written to it.

        return: (logfile, scorelist) if the test was run through. Assuming this
                happens, scores will be written to the logfile
        return: (-1,-1) if the task was quit prior to the completion of the
                study phase, meaning scores will not be writtent to the logfile
        """

        #Print task ending message to the screen, and wait escape to be prssed
        def EndExp():
            exitPrompt = ("This concludes the session. Thank you for "
                          "participating!\n\nPress Esc to quit")
            exitText = TextStim(self.window, exitPrompt, color='Black')
            exitText.draw(self.window)
            self.window.flip()
            waitKeys(keyList=['escape'])
            self.window.close()

        # Show main welcome window
        welcomePrompt = "Thank you for participating in our study! Press '{}' to begin".format(
            self.pauseButton)
        self.ShowPromptAndWaitForSpace(welcomePrompt)

        # If run practice trials, then RunPractice
        if self.runPracticeTrials:
            self.RunPractice()

        #Run study, terminate if user exits early
        studyFinished = self.RunStudy()
        testFinished = self.RunTest()

        if (not studyFinished):
            EndExp()
            self.logfile.close()
            return (-1, -1)

        EndExp()
        return (self.logfile, self.scoreList)