def test_element_array_colors(self): # Create element array with two elements covering the whole window in two block colours obj = visual.ElementArrayStim(self.win, units="pix", fieldPos=(0, 0), fieldSize=(128, 128), fieldShape='square', nElements=2, sizes=[[64, 128], [64, 128]], xys=[[-32, 0], [32, 0]], elementMask=None, elementTex=None) # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: if space not in colors.strSpaces and not isinstance( colorSet[space], (str, type(None))): # Check that setting color arrays renders correctly obj.colorSpace = space col1 = np.array(colorSet[space]).reshape((1, -1)) col2 = getattr(colors.Color('black'), space).reshape( (1, -1)) obj.colors = np.append( col1, col2, 0 ) # Set first color to current color set, second to black in same color space obj.opacity = 1 # Fix opacity at full as this is not what we're testing self.win.flip() obj.draw() utils.comparePixelColor(self.win, colors.Color( colorSet[space], space), coord=(10, 10)) utils.comparePixelColor(self.win, colors.Color('black'), coord=(10, 100))
def test_color_operators(): """Test for operators used to compare colors.""" red255 = colors.Color((255, 0, 0), space='rgb255') redRGB = colors.Color((1, -1, -1), space='rgb') redRGB1 = colors.Color((1, 0, 0), space='rgb1') assert (red255 == redRGB == redRGB1)
def test_shape_colors(): # Create rectangle with chunky border obj = visual.Rect(win, units="pix", pos=(0, 0), size=(128, 128), lineWidth=10) # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: # Check border color obj.colorSpace = space obj.borderColor = colorSet[space] obj.fillColor = 'white' obj.opacity = 1 # Fix opacity at full as this is not what we're testing win.flip() obj.draw() utils.comparePixelColor(win, colors.Color(colorSet[space], space), coord=(1, 1)) utils.comparePixelColor(win, colors.Color('white'), coord=(50, 50)) # Check fill color obj.colorSpace = space obj.fillColor = colorSet[space] obj.borderColor = 'white' obj.opacity = 1 # Fix opacity at full as this is not what we're testing win.flip() obj.draw() utils.comparePixelColor(win, colors.Color('white'), coord=(1, 1)) utils.comparePixelColor(win, colors.Color(colorSet[space], space), coord=(50, 50))
def test_element_array_colors(): # Create element array with two elements covering the whole window in two block colours obj = visual.ElementArrayStim(win, units="pix", fieldPos=(0, 0), fieldSize=(128, 128), fieldShape='square', nElements=2, sizes=[[64, 128], [64, 128]], xys=[[-32, 0], [32, 0]], elementMask=None, elementTex=None) # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: # Check that setting color arrays renders correctly obj.colorSpace = space obj.colors = [ colorSet[space], 'black' ] # Set first color to current color set, second to black obj.opacity = 1 # Fix opacity at full as this is not what we're testing win.flip() obj.draw() utils.comparePixelColor(win, colors.Color(colorSet[space], space), coord=(10, 10)) utils.comparePixelColor(win, colors.Color('black'), coord=(10, 100))
def _findColors(win): """ The window background is set to red, the max guides are white, the min guides are blue, and the dots are black at 50% opacity. If fieldSize is correct, dots should only be visible against guides, not background - so there should be grey and dark blue pixels, with no dark red pixels. """ # Define acceptable margin of error (out of 255) err = 5 # Get screenshot img = np.array(win._getFrame(buffer="back")) # Flatten screenshot img = img.flatten() # Unflatten screenshot to pixel level img = img.reshape((-1, 3)) # Get unique colors cols = np.unique(img, axis=0) # Define colors to seek/avoid darkblue = colors.Color( (np.array([-1, -1, 1]) + np.array([-1, -1, -1])) / 2, "rgb") grey = colors.Color( (np.array([1, 1, 1]) + np.array([-1, -1, -1])) / 2, "rgb") darkred = colors.Color( (np.array([1, -1, -1]) + np.array([-1, -1, -1])) / 2, "rgb") # We want dark blue - it means the middle is drawn inrange = np.logical_and((darkblue.rgb255 - err) < cols, cols < (darkblue.rgb255 + err)) inrange = np.all(inrange, axis=1) assert np.any(inrange), ( f"No pixel of color {darkblue.rgb255} found in dotstim, meaning the middle of the field is not drawn.\n" f"\n" f"Colors found:\n" f"{cols}") # We want grey - it means the edges are drawn inrange = np.logical_and((grey.rgb255 - err) < cols, cols < (grey.rgb255 + err)) inrange = np.all(inrange, axis=1) assert np.any(inrange), ( f"No pixel of color {grey.rgb255} found in dotstim, meaning the field of dots is too small.\n" f"\n" f"Colors found:\n" f"{cols}") # We don't want dark red - it means there are dots outside the field inrange = np.logical_and((darkred.rgb255 - err) < cols, cols < (darkred.rgb255 + err)) inrange = np.all(inrange, axis=1) assert not np.any(inrange), ( f"Pixel of color {darkred.rgb255} found in dotstim, meaning the field of dots is too big.\n" f"\n" f"Colors found:\n" f"{cols}")
def test_colors(self): for colorSet in exemplars + tykes: # Construct matrix of space pairs spaceMatrix = [] for space1 in colorSet: spaceMatrix.extend([[space1, space2] for space2 in colorSet if space2 != space1]) # Compare each space pair for consistency for space1, space2 in spaceMatrix: col1 = colors.Color(colorSet[space1], space1) col2 = colors.Color(colorSet[space2], space2) closeEnough = all(abs(col1.rgba[i]-col2.rgba[i])<0.02 for i in range(4)) # Check that valid color has been created assert (bool(col1) and bool(col2)) # Check setters assert (col1 == col2 or closeEnough)
def test_contrast(self): # Create rectangle with chunky border obj = visual.Rect(self.win, units="pix", pos=(0, 0), size=(128, 128), lineWidth=10) # Set its colors to be rgb extremes obj.fillColor = 'red' obj.borderColor = 'blue' obj.opacity = 1 # Fix opacity at full as this is not what we're testing # Halve contrast obj.contrast = 0.5 # Refresh self.win.flip() obj.draw() # Check rendered color utils.comparePixelColor(self.win, colors.Color(( 0.5, -0.5, -0.5), "rgb"), coord=(50, 50)) utils.comparePixelColor(self.win, colors.Color((-0.5, -0.5, 0.5), "rgb"), coord=(1, 1))
def test_window_colors(): # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: # Set window color win.colorSpace = space win.color = colorSet[space] win.flip() utils.comparePixelColor(win, colors.Color(colorSet[space], space))
def test_visual_helper(self): # Create rectangle with chunky border obj = visual.Rect(self.win, units="pix", pos=(0, 0), size=(128, 128), lineWidth=10) # Iterate through color sets for colorSet in exemplars + tykes: for space in colorSet: # Check border color visual.helpers.setColor(obj, color=colorSet[space], colorSpace=space, colorAttrib="borderColor") obj.fillColor = 'white' obj.opacity = 1 # Fix opacity at full as this is not what we're testing self.win.flip() obj.draw() if colorSet[space]: # skip this comparison if color is None utils.comparePixelColor(self.win, colors.Color(colorSet[space], space), coord=(1, 1)) utils.comparePixelColor(self.win, colors.Color('white'), coord=(50, 50)) # Check fill color visual.helpers.setColor(obj, color=colorSet[space], colorSpace=space, colorAttrib="fillColor") obj.borderColor = 'white' obj.opacity = 1 # Fix opacity at full as this is not what we're testing self.win.flip() obj.draw() if colorSet[space]: # skip this comparison if color is None utils.comparePixelColor(self.win, colors.Color(colorSet[space], space), coord=(50, 50)) utils.comparePixelColor(self.win, colors.Color('white'), coord=(1, 1)) # Check color addition obj.fillColor = 'white' visual.helpers.setColor(obj, color='black', colorAttrib='fillColor', operation='+') self.win.flip() obj.draw() utils.comparePixelColor(self.win, colors.Color('white') + colors.Color('black'), coord=(50, 50)) # Check color subtraction obj.fillColor = 'grey' visual.helpers.setColor(obj, color='black', colorAttrib='fillColor', operation='-') self.win.flip() obj.draw() utils.comparePixelColor(self.win, colors.Color('grey') - colors.Color('black'), coord=(50, 50)) # Check alerts visual.helpers.setColor(obj, color="white", colorSpaceAttrib="fillColorSpace", rgbAttrib="fillRGB") assert any(err.code == 8105 for err in self.error.alerts), "Alert 8105 not triggered" assert any(err.code == 8110 for err in self.error.alerts), "Alert 8110 not triggered"
def setColor( obj, color, colorSpace=None, operation='', colorAttrib='color', # or 'fillColor' etc # legacy colorSpaceAttrib=None, rgbAttrib=None, log=True): """ Sets the given color attribute of an object. Obsolete as of 2021.1.0, as colors are now handled by Color objects, all of the necessary operations are called when setting directly via obj.color, obj.fillColor or obj.borderColor. obj : psychopy.visual object The object whose color you are changing color : color The color to use - can be a valid color value (e.g. (1,1,1), '#ffffff', 'white') or a psychopy.colors.Color object colorSpace : str The color space of the color value. Can be None for hex or named colors, otherwise must be specified. operation : str Can be '=', '+' or '-', or left blank for '='. '=' will set the color, '+' will add the color and '-' will subtract it. colorAttrib : str Name of the color attribute you are setting, e.g. 'color', 'fillColor', 'borderColor' Legacy --- colorSpaceAttrib : str PsychoPy used to have a color space for each attribute, but color spaces are now handled by Color objects, so this input is no longer used. rgbAttrib : str PsychoPy used to handle color by converting to RGB and storing in an rgb attribute, now this conversion is done within Color objects so this input is no longer used. log : bool log argument is deprecated - has no effect now. Logging should be done when setColor() is called. """ if colorSpaceAttrib is not None: alert(8105, strFields={'colorSpaceAttrib': colorSpaceAttrib}) if rgbAttrib is not None: alert(8110, strFields={'rgbAttrib': rgbAttrib}) # Make a Color object using supplied values raw = color color = colors.Color(raw, colorSpace) assert color.valid, f"Could not create valid Color object from value {raw} in space {colorSpace}" # Apply new value if operation in ('=', '', None): # If no operation, just set color from object setattr(obj, colorAttrib, color) elif operation == '+': # If +, add to old color setattr(obj, colorAttrib, getattr(obj, "_" + colorAttrib) + color) elif operation == '-': # If -, subtract from old color setattr(obj, colorAttrib, getattr(obj, "_" + colorAttrib) - color) else: # Any other operation is not supported msg = ('Unsupported value "%s" for operation when ' 'setting %s in %s') vals = (operation, colorAttrib, obj.__class__.__name__) raise ValueError(msg % vals)
def test_colors(self): # If this test object has no obj, skip if not self.obj: return # Test each case for case in self.colorTykes + self.colorExemplars: for space, color in case.items(): # Make color to compare against target = colors.Color(color, space) # Prepare object self.obj.colorSpace = space self.obj.fillColor = 'white' self.obj.foreColor = 'white' self.obj.borderColor = 'white' self.obj.opacity = 1 if hasattr(self.obj, "text"): self.obj.text = "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question." # Prepare window self.win.flip() # Test fill color if self.fillUsed: # Set fill self.obj.fillColor = color self.obj.opacity = 1 self.obj.draw() if color is not None: # Make sure fill is set utils.comparePixelColor(self.win, target, coord=self.fillPoint, context=f"{self.__class__.__name__}_fill") # Make sure border is not if self.borderUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.borderPoint, context=f"{self.__class__.__name__}_fill") # Make sure fore is not if self.foreUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.forePoint, context=f"{self.__class__.__name__}_fill") # Reset fill self.obj.fillColor = 'white' self.obj.opacity = 1 # Test border color if self.borderUsed: # Set border self.obj.borderColor = color self.obj.opacity = 1 self.obj.draw() if color is not None: # Make sure border is set utils.comparePixelColor(self.win, target, coord=self.borderPoint, context=f"{self.__class__.__name__}_border") # Make sure fill is not if self.fillUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.fillPoint, context=f"{self.__class__.__name__}_border") # Make sure fore is not if self.foreUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.forePoint, context=f"{self.__class__.__name__}_border") # Reset border self.obj.borderColor = 'white' self.obj.opacity = 1 # Test fore color if self.foreUsed: # Set fore self.obj.foreColor = color self.obj.opacity = 1 self.obj.draw() if color is not None: # Make sure fore is set utils.comparePixelColor(self.win, target, coord=self.forePoint, context=f"{self.__class__.__name__}_fore") # Make sure fill is not if self.fillUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.fillPoint, context=f"{self.__class__.__name__}_fore") # Make sure border is not if self.borderUsed: utils.comparePixelColor(self.win, colors.Color('white'), coord=self.borderPoint, context=f"{self.__class__.__name__}_fore") # Reset fore self.obj.foreColor = 'white' self.obj.opacity = 1
def test_legacy_setters(self): # If this test object has no obj, skip if not self.obj: return # Test each case for case in self.colorTykes + self.colorExemplars: for space, color in case.items(): if color is None: continue # Make color to compare against target = colors.Color(color, space) # Prepare object self.obj.colorSpace = space self.obj.fillColor = 'white' self.obj.foreColor = 'white' self.obj.borderColor = 'white' self.obj.opacity = 1 if hasattr(self.obj, "text"): self.obj.text = "A PsychoPy zealot knows a smidge of wx, but JavaScript is the question." # Test property aliases: # color == foreColor self.obj.color = color assert self.obj._foreColor == target self.obj.color = colors.Color('white') self.obj.opacity = 1 # backColor == fillColor self.obj.backColor = color assert self.obj._fillColor == target self.obj.backColor = colors.Color('white') self.obj.opacity = 1 # lineColor == borederColor self.obj.lineColor = color assert self.obj._borderColor == target self.obj.lineColor = colors.Color('white') self.obj.opacity = 1 if space == 'rgb': # Test RGB properties # foreRGB self.obj.foreRGB = color assert self.obj._foreColor == target self.obj.foreRGB = colors.Color('white') self.obj.opacity = 1 # RGB self.obj.RGB = color assert self.obj._foreColor == target self.obj.RGB = colors.Color('white') self.obj.opacity = 1 # fillRGB self.obj.fillRGB = color assert self.obj._fillColor == target self.obj.fillRGB = colors.Color('white') self.obj.opacity = 1 # backRGB self.obj.backRGB = color assert self.obj._fillColor == target self.obj.backRGB = colors.Color('white') self.obj.opacity = 1 # borderRGB self.obj.borderRGB = color assert self.obj._borderColor == target self.obj.borderRGB = colors.Color('white') self.obj.opacity = 1 # lineRGB self.obj.lineRGB = color assert self.obj._borderColor == target self.obj.lineRGB = colors.Color('white') self.obj.opacity = 1 # Test RGB methods # setRGB self.obj.setRGB(color) assert self.obj._foreColor == target self.obj.setRGB('white') self.obj.opacity = 1 # setFillRGB self.obj.setFillRGB(color) assert self.obj._fillColor == target self.obj.setFillRGB('white') self.obj.opacity = 1 # setBackRGB self.obj.setBackRGB(color) assert self.obj._fillColor == target self.obj.setBackRGB('white') self.obj.opacity = 1 # setBorderRGB self.obj.setBorderRGB(color) assert self.obj._borderColor == target self.obj.setBorderRGB('white') self.obj.opacity = 1 # setLineRGB self.obj.setLineRGB(color) assert self.obj._borderColor == target self.obj.setLineRGB('white') self.obj.opacity = 1 # Test methods: # setForeColor self.obj.setForeColor(color) assert self.obj._foreColor == target self.obj.setForeColor('white') self.obj.opacity = 1 # setColor self.obj.setColor(color) assert self.obj._foreColor == target self.obj.setColor('white') self.obj.opacity = 1 # setFillColor self.obj.setFillColor(color) assert self.obj._fillColor == target self.obj.setFillColor('white') self.obj.opacity = 1 # setBackColor self.obj.setBackColor(color) assert self.obj._fillColor == target self.obj.setBackColor('white') self.obj.opacity = 1 # setBorderColor self.obj.setBorderColor(color) assert self.obj._borderColor == target self.obj.setBorderColor('white') self.obj.opacity = 1 # setLineColor self.obj.setLineColor(color) assert self.obj._borderColor == target self.obj.setLineColor('white') self.obj.opacity = 1 # Test old color space setters # foreColorSpace self.obj.foreColorSpace = space assert self.obj.colorSpace == space self.obj.foreColorSpace = 'named' # fillColorSpace self.obj.fillColorSpace = space assert self.obj.colorSpace == space self.obj.fillColorSpace = 'named' # backColorSpace self.obj.backColorSpace = space assert self.obj.colorSpace == space self.obj.backColorSpace = 'named' # borderColorSpace self.obj.borderColorSpace = space assert self.obj.colorSpace == space self.obj.borderColorSpace = 'named' # lineColorSpace self.obj.lineColorSpace = space assert self.obj.colorSpace == space self.obj.lineColorSpace = 'named'
letterHeight=0.03, color='white', borderColor=None, fillColor=None) while not endBtn.isClicked: # Try to make a fillColor, make it False if failed try: val = valueCtrl.text # If input looks like a number, convert it if val.isnumeric(): val = float(val) # If input looks like an array, un-stringify it if "," in val: val = eval(val) # Get color space from radio slider space = spaces[int(spaceCtrl.value)] col = colors.Color(val, space) except: col = False # Set the color box's fill color, show text "invalid" if color is invalid if col: colorBox.text = "" colorBox.fillColor = col else: colorBox.text = "invalid color" colorBox.fillColor = None # Draw stim and flip for stim in (valueCtrl, endBtn, colorBox, spaceCtrl, instrBox): stim.draw() win.flip()
def setup_class(cls): nFrames = 16 # Define array of sizes/desired frame rates cls.cases = [ { 'size': 6**2, 'fps': 16 }, { 'size': 8**2, 'fps': 16 }, { 'size': 10**2, 'fps': 8 }, { 'size': 12**2, 'fps': 2 }, ] # Create frames for i, case in enumerate(cls.cases): size = case['size'] # Create window and shapes win = visual.Window(size=(size, size), color='purple') shape1 = visual.ShapeStim( win, pos=(0.2, 0.2), size=(0.5, 0.5), lineWidth=size * 0.1, fillColor='red', lineColor='green', ) shape2 = visual.ShapeStim(win, pos=(-0.2, -0.2), size=(0.5, 0.5), lineWidth=size * 0.1, fillColor='blue', lineColor='yellow') frames = [] for thisFrame in range(nFrames): # Cycle window hue win.color = colors.Color( (win._color.hsv[0] + 360 * thisFrame / nFrames, win._color.hsv[1], win._color.hsv[2]), 'hsv') # Cycle shape hues shape1._fillColor.hsv = (shape1._fillColor.hsv[0] + 360 * thisFrame / nFrames, shape1._fillColor.hsv[1], shape1._fillColor.hsv[2]) shape1._borderColor.hsv = (shape1._borderColor.hsv[0] - 360 * thisFrame / nFrames, shape1._borderColor.hsv[1], shape1._borderColor.hsv[2]) shape2._fillColor.hsv = (shape2._fillColor.hsv[0] + 360 * thisFrame / nFrames, shape2._fillColor.hsv[1], shape2._fillColor.hsv[2]) shape2._borderColor.hsv = (shape2._borderColor.hsv[0] - 360 * thisFrame / nFrames, shape2._borderColor.hsv[1], shape2._borderColor.hsv[2]) # Rotate shapes shape1.ori = shape1.ori + 360 * thisFrame / nFrames shape2.ori = shape2.ori - 360 * thisFrame / nFrames # Render win.flip() shape1.draw() shape2.draw() # Get frame frame = win.getMovieFrame(buffer='back') frames.append(frame) # Cleanup win.close() del shape1 del shape2 # Update case cls.cases[i]['frames'] = frames