Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Supported by

Speeding up (vectorising?) a for loop

edited May 2016 in OpenSesame

We are developing a dynamic visual search experiment, where a number of dots move randomly around the screen. The code involves a series of for loops (an extract from the code is pasted in below). Our issue is that as NStim increases, the time taken to execute the for loops increases, meaning that the dots are moving slower when there are more of them. Is it possible to vectorise the code in order to avoid this problem? (sorry, we have some experience with Matlab but not with Python). We'd really like the dots to move at the same speed!

Thanks!

# Loop through all frames
for j in range(NFrames):

        # For each frame, clear the canvas and then loop through all stimuli
        myCanvas.clear()
        for i in range(NStim):
                # Get the stimulus properties
                x, y, a, v, r = stimList[i]
                # Update the position of the stimulus based on the angle and the speed
                x += v * math.cos(a)
                y += v * math.sin(a)   
                # If the stimulus leaves the screen, reverse direction by 180 deg (= 1pi radial)
                if x <= 0 or x >= self.get('width') or y <= 0 or y >= self.get('height'):
                        a = a + math.pi
                else:
                        # else randomly rotate the stimulus a bit
                        a += (random.random()-.5) * maxRotSpeed                
                # Highlight the targets on the first frame
                if i < NTarget and j == 0:
                        color = targetColor
                else:
                        color = normalColor                    
                # Draw the stimulus
                myCanvas.circle(x, y, r, fill=True, color=color)
                # Store the new stimulus properties back in the stimulus list
                stimList[i] = x, y, a, v, r
        # Show the canvas      
        myCanvas.show()
        # Sleep after the first frame so that the participant can identify the targets
        if j == 0:
                self.sleep(firstFrameDur)
# Store the coordinates of the stimuli in the last frame, in order to compare
# the mouse click responses with the actual positions

Comments

  • edited 7:35AM

    Hi,

    Rendering the stimuli like this is not optimal, but in most cases it should be fast enough. What I think might be going on is that you're using the xpyriment back-end, and have not set the auto_prepare keyword to False when creating canvas objects (it's True by default). When auto_prepare is True the canvas will be prepared for being flipped to the display after every drawing operation, which takes a bit of time. If you set it to False, drawing will go much faster, but you have to explicitly call canvas.prepare(). This is illustrated in the example:

    This, by the way, is currently specific to the xpyriment backend.

    Does this help? If not, there are plenty of other ways to speed up rendering.

    Cheers,
    Sebastiaan

  • edited 7:35AM

    Hi Sebastiaan,

    thanks for your reply! We're actually not using xpyriment backend (I just ran it using xpyriment and it was REALLY slow). It is much faster/smoother in pyscho & legacy, but there is still a slight speed difference between the Nstim sizes (i.e. 5 dots move quicker than >5 dots), which isn't ideal.

    Thanks,
    Khia

  • edited May 2016

    In that case, it's probably best to really implement this properly, using PsychoPy, which allows you to update stimuli on the fly. So you don't need to clear the canvas and redraw everything from scratch, but rather simply change the position of stimuli. This is much faster, so you should be able to draw as many stimuli as you want.

    Below you see an example script that does more or less what you need. You can just copy-paste it into an inline_script. I also wrapped the moving dot into a nice class, so that the code remains clean. But I don't think you need any real knowledge of object-oriented programming to use this.

    Does this get you started?

    from psychopy import visual
    import random
    import math
    
    nstim = 10
    nframes = 500
    
    class MovingDot:
    
        """
        A single moving dot.
        """
    
        def __init__(self, x, y, v, d, maxrot):
    
            """
            Create a new dot.
    
            x -- starting x coordinate
            y -- starting y coordinate
            v -- starting velocity in px per frame
            d -- starting direction in radial angle
            maxrot -- the maximum random rotation of the angle.
            """
    
            self._v = v
            self._d = d
            self._maxrot = maxrot
            self._circle = visual.Circle(win, radius=20, pos=(x,y))
    
        def draw(self):
    
            """
            Draw the dot, but don't update the display.
            """
    
            self._circle.draw()
    
        def move(self):
    
            """
            Move the dot and handle direction reversals etc.
            """
    
            x, y = self._circle.pos
            dx = math.cos(self._d) * self._v
            dy = math.sin(self._d) * self._v
            # Reverse direction if the dot leaves the screen
            if abs(x+dx) > var.width/2 or abs(y+dy) > var.height/2:
                self._d += math.pi
                self.move()
                return
            self._circle.pos = x+dx, y+dy
            self._d += (random.random()-.5) * self._maxrot
    
    # Create a list of moving dots
    mdlist = []
    for i in range(nstim):
        md = MovingDot(x=0, y=0, v=10, d=random.random()*2*math.pi, maxrot=.5)
        mdlist.append(md)
    
    # Draw all moving dots
    for i in range(nframes):
        for md in mdlist:
            md.move()
            md.draw()
        win.flip()
    
  • edited 7:35AM

    That's great thank you Sebastiaan!

    Seeing as you have been so helpful, do you happen to know if/how I can interrupt the trial before nframe runs to its end? So nframe would be the maximum run length of a trial before time-out but the trial could be halted at any point before that by moving the mouse and having the cursor appear on the screen.

    I would like to be able to move the cursor in the trial window before the max nframe so I can select a target (that is then recorded with the data logger before a new trial begins).

    Many thanks,

    Khia

Sign In or Register to comment.

agen judi bola , sportbook, casino, togel, number game, singapore, tangkas, basket, slot, poker, dominoqq, agen bola. Semua permainan bisa dimainkan hanya dengan 1 ID. minimal deposit 50.000 ,- bonus cashback hingga 10% , diskon togel hingga 66% bisa bermain di android dan IOS kapanpun dan dimana pun. poker , bandarq , aduq, domino qq , dominobet. Semua permainan bisa dimainkan hanya dengan 1 ID. minimal deposit 10.000 ,- bonus turnover 0.5% dan bonus referral 20%. Bonus - bonus yang dihadirkan bisa terbilang cukup tinggi dan memuaskan, anda hanya perlu memasang pada situs yang memberikan bursa pasaran terbaik yaitu http://45.77.173.118/ Bola168. Situs penyedia segala jenis permainan poker online kini semakin banyak ditemukan di Internet, salah satunya TahunQQ merupakan situs Agen Judi Domino66 Dan BandarQ Terpercaya yang mampu memberikan banyak provit bagi bettornya. Permainan Yang Di Sediakan Dewi365 Juga sangat banyak Dan menarik dan Peluang untuk memenangkan Taruhan Judi online ini juga sangat mudah . Mainkan Segera Taruhan Sportbook anda bersama Agen Judi Bola Bersama Dewi365 Kemenangan Anda Berapa pun akan Terbayarkan. Tersedia 9 macam permainan seru yang bisa kamu mainkan hanya di dalam 1 ID saja. Permainan seru yang tersedia seperti Poker, Domino QQ Dan juga BandarQ Online. Semuanya tersedia lengkap hanya di ABGQQ. Situs ABGQQ sangat mudah dimenangkan, kamu juga akan mendapatkan mega bonus dan setiap pemain berhak mendapatkan cashback mingguan. ABGQQ juga telah diakui sebagai Bandar Domino Online yang menjamin sistem FAIR PLAY disetiap permainan yang bisa dimainkan dengan deposit minimal hanya Rp.25.000. DEWI365 adalah Bandar Judi Bola Terpercaya & resmi dan terpercaya di indonesia. Situs judi bola ini menyediakan fasilitas bagi anda untuk dapat bermain memainkan permainan judi bola. Didalam situs ini memiliki berbagai permainan taruhan bola terlengkap seperti Sbobet, yang membuat DEWI365 menjadi situs judi bola terbaik dan terpercaya di Indonesia. Tentunya sebagai situs yang bertugas sebagai Bandar Poker Online pastinya akan berusaha untuk menjaga semua informasi dan keamanan yang terdapat di POKERQQ13. Kotakqq adalah situs Judi Poker Online Terpercayayang menyediakan 9 jenis permainan sakong online, dominoqq, domino99, bandarq, bandar ceme, aduq, poker online, bandar poker, balak66, perang baccarat, dan capsa susun. Dengan minimal deposit withdraw 15.000 Anda sudah bisa memainkan semua permaina pkv games di situs kami. Jackpot besar,Win rate tinggi, Fair play, PKV Games