如何制作一个圆形视觉对象,其面积平均分为三种或更多种颜色?

How can I make a circular visual object with its area evenly divided among three or more colors?

背景:

对 python 和精神病学有点陌生。我正在尝试构建一个可以在功能上复制轮盘的功能,我基本上已经这样做了。此功能将围绕一个大圆圈旋转一个小圆圈,并在旋转时按 'space' 将启动小圆圈的公转速度的指数减速。为了模拟轮盘(较大的圆圈),我使用了 PsychoPy 中的 visual.RadialStim 组件。据我所知,它确实是为了方便地构建旋转棋盘视觉效果而设计的,这些视觉效果通常用作 fMRI 实验中的控件。然而,这意味着它将轮子均匀地分成交替的颜色部分,这对我的目的很有帮助。这是正在执行的任务的可视化:

问题:

我希望能够在色盘上放置两种以上的颜色,但我不确定 visual.RadialStim 是否可行。查看文档,我看不出有什么帮助,不过,我确实遇到了这个 old thread ,乔恩似乎暗示这是可能的,但坦率地说,我无法弄清它的正面或反面,我认为 OP 也没有解决它。有谁知道我对 RadialStim 的怀疑是否正确(即不能使用两种以上的颜色)?或者,有没有人有其他推荐的解决方案来替换它,这样我就可以在这个更大的圆圈上模拟 3 或 4 种颜色?

代码:

请注意 - 对于那些不熟悉 PsychoPy 的人,它是一个专门为创建研究而构建的集合函数,并且需要任何使用它的代码在 PsychoPy 终端中 运行(而不是任何旧的 Python终端)。 PsychoPy 可以 运行 任何 Python 包,但是 Python 终端不能 运行 PsychoPy 代码,所以如果你试图在没有 PsychoPy 的情况下自己 运行 这个,它可能行不通。

# Psychopy modules
from psychopy import core, event, visual, gui
# Needed to calculate the trajectory of the revolving ball
import math
# Needed to calculcate the deceleration of the revolving ball
import random

# Specifying which monitor to use
monitor=0

# The speed with which the ball revolves around the wheel
speed = 0.125

# The radius of the wheel around which the ball is revolving
wheel_radius=0.45

# How many frames per second the animation should use
fps = 30
 
# Specifying Window & Screen Information -----
win = visual.Window(size=(1024, 768), 
                    fullscr=True, 
                    screen= monitor, 
                    winType='pyglet', 
                    allowGUI=True, 
                    allowStencil=False,
                    monitor='testMonitor', 
                    color=[0,0,0], 
                    colorSpace='rgb',
                    blendMode='avg', 
                    useFBO=True, 
                    units='height')

# Noting the starting position of the revolving ball
position = 0.0

# Noting whether the ball is decelerating
decelerate = False

# Creating the ball
ball = visual.Circle(win, edges=100,radius=0.02, fillColor='white', lineColor=None, pos=[position,position])

# Creating the wheel
wheel = visual.RadialStim(win, pos=(0,0), size=((wheel_radius * 2), (wheel_radius * 2)),
                          color =('red', 'blue', 'white'), angularRes=300, 
                          angularCycles=6, radialCycles = 0, opacity= 0.8, autoLog=False)

# While speed is greater than 0:
while speed > 0:

    # Change the position of the ball according to the current value of position
    ball.pos = [((math.sin(position)/10) * (wheel_radius * 10)),
                ((math.cos(position)/10) * (wheel_radius * 10))]

    # Produce the visualization of the wheel            
    wheel.draw()

    # Produce the visualization of the ball
    ball.draw()

    # If the participant hasn't asked to stop the spinner yet
    if decelerate == False:

        # Continue spinning the ball around the wheel according to the specified speed
        position += speed
    
    # If the participant has asked to stop the spinner
    if decelerate == True:

        # Randomly select a value between 0.005 and 0.035
        rand_dec = random.uniform(0.005,0.035)

        # Reduce speed to be a percentage (99.5% - 96.5%) of its last value
        # Randomizing the the value of the deceleration will hopefully prevent 
        # participants from being able to predict where the ball will stop. Also
        # making speed a fraction or what it once was, rather than using a linear value
        # will better model friction and exponential decay in the real world
        speed *= 1 - rand_dec

        # Continue spinning the ball around the wheel according to the new speed
        position += speed

    # If speed drops below 0.001
    if speed < 0.001:
        # Round speed down to 0
        speed = 0

    # If escape is pressed, end the task
    if event.getKeys('escape'):
        break      

    # If space is pressed, begin slowing the ball
    if event.getKeys('space'):
        decelerate = True

    # Refresh the screen according to the core.wait rate allowing for objects and visualizations
    # to change position
    win.flip()

    # How long psychopy should wait before updating the screen   
    core.wait(1/fps)

# close the window
win.close()

尽我所能,我无法使纹理方法起作用,但我选择了一个少得多的 eloquent 解决方案。通过降低 RadialStim 的不透明度并以半不透明度覆盖另一个补色的 RadialStim,并以 30 度角放置,我能够或多或少地创建四种颜色的外观。不激动,但现在就可以了。期待其他人出现。

# Psychopy modules
from psychopy import core, event, visual, gui
# Needed to calculate the trajectory of the revolving ball
import math
# Needed to calculcate the deceleration of the revolving ball
import random
# Needed to create colors for the roulette wheel
import numpy as np

# Specifying which monitor to use
monitor=0

# The speed with which the ball revolves around the wheel
speed = 0.125

# The radius of the wheel around which the ball is revolving
wheel_radius=0.45

# How many frames per second the animation should use
fps = 30
 
# Specifying Window & Screen Information -----
win = visual.Window(size=(1024, 768), 
                    fullscr=True, 
                    screen= monitor, 
                    winType='pyglet', 
                    allowGUI=True, 
                    allowStencil=False,
                    monitor='testMonitor', 
                    color=[0,0,0], 
                    colorSpace='rgb',
                    blendMode='avg', 
                    useFBO=True, 
                    units='height')

# Noting the starting position of the revolving ball
position = 0.0

# Noting whether the ball is decelerating
decelerate = False

# Creating the ball
ball = visual.Circle(win, edges=100,radius=0.02, fillColor='white', lineColor=None, pos=[position,position])

# Creating the wheel
wheel_base = visual.RadialStim(win, pos=(0,0), size=((wheel_radius * 2), (wheel_radius * 2)),
                          color ='yellow', angularRes=300,
                          angularCycles=3, radialCycles = 0, opacity= 0.9, autoLog=False)
wheel_layer = visual.RadialStim(win, pos=(0,0), size=((wheel_radius * 2), (wheel_radius * 2)),
                          color ='red', angularRes=300, ori=30,
                          angularCycles=3, radialCycles = 0, opacity= 0.5, autoLog=False)


# While speed is greater than 0:
while speed > 0:

    # Change the position of the ball according to the current value of position
    ball.pos = [((math.sin(position)/10) * (wheel_radius * 10)),
                ((math.cos(position)/10) * (wheel_radius * 10))]

    # Produce the visualization of the wheel            
    wheel_base.draw()
    wheel_layer.draw()

    # Produce the visualization of the ball
    ball.draw()

    # If the participant hasn't asked to stop the spinner yet
    if decelerate == False:

        # Continue spinning the ball around the wheel according to the specified speed
        position += speed
    
    # If the participant has asked to stop the spinner
    if decelerate == True:

        # Reduce speed to be a percentage (99.5% - 96.5%) of its last value
        # Randomizing the the value of the deceleration will hopefully prevent 
        # participants from being able to predict where the ball will stop. Also
        # making speed a fraction or what it once was, rather than using a linear value
        # will better model friction and exponential decay in the real world
        speed *= 1 - rand_dec

        # Continue spinning the ball around the wheel according to the new speed
        position += speed

    # If speed drops below 0.001
    if speed < 0.001:
        # Round speed down to 0
        speed = 0

    # If escape is pressed, end the task
    if event.getKeys('escape'):
        break      

    # If space is pressed, begin slowing the ball
    if event.getKeys('space'):
        decelerate = True
        
        # Randomly select a value between 0.005 and 0.035
        rand_dec = random.uniform(0.005,0.035)

    # Refresh the screen according to the core.wait rate allowing for objects and visualizations
    # to change position
    win.flip()

    # How long psychopy should wait before updating the screen   
    core.wait(1/fps)

# close the window
win.close()