Skip to content

Commit

Permalink
Merge pull request #2652 from mdcutone/pie-stim
Browse files Browse the repository at this point in the history
NF: `Pie` shape class for pac-man shapes.
  • Loading branch information
peircej committed Oct 15, 2019
2 parents 8db8521 + 035e57e commit 584d586
Show file tree
Hide file tree
Showing 4 changed files with 225 additions and 0 deletions.
8 changes: 8 additions & 0 deletions docs/source/api/visual/pie.rst
@@ -0,0 +1,8 @@


:class:`Pie`
------------------------------------
.. autoclass:: psychopy.visual.Pie
:members:
:undoc-members:
:inherited-members:
41 changes: 41 additions & 0 deletions psychopy/demos/coder/stimuli/kanizsa.py
@@ -0,0 +1,41 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Demo for the class psychopy.visual.Pie().
Use the `Pie` class to create a Kanizsa figure which produces illusory
contours.
"""
from psychopy import core
import psychopy.visual as visual
from psychopy.visual import Pie
from psychopy import event

# open a window to render the shape
win = visual.Window((600, 600), allowGUI=False, monitor='testMonitor')

# create the stimulus object
pieStim = Pie(
win, radius=50, start=0., end=270., fillColor=(-1., -1., -1.), units='pix')

message = visual.TextStim(
win, text='Any key to quit', pos=(0, -0.8), units='norm')

# positions of the corners of the shapes
pos = [(-100, 100), (100, 100), (-100, -100), (100, -100)]

# orientations of the shapes
ori = [180., 270., 90., 0.]

while not event.getKeys():

for i in range(4):
pieStim.pos = pos[i]
pieStim.ori = ori[i]
pieStim.draw()

message.draw()
win.flip()

win.close()
core.quit()
1 change: 1 addition & 0 deletions psychopy/visual/__init__.py
Expand Up @@ -75,6 +75,7 @@
from psychopy.visual.line import Line
from psychopy.visual.polygon import Polygon
from psychopy.visual.rect import Rect
from psychopy.visual.pie import Pie
# stimuli derived from Polygon
from psychopy.visual.circle import Circle
Expand Down
175 changes: 175 additions & 0 deletions psychopy/visual/pie.py
@@ -0,0 +1,175 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""Create a pie shape."""

# Part of the PsychoPy library
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019 Open Science Tools Ltd.
# Distributed under the terms of the GNU General Public License (GPL).

from __future__ import absolute_import, print_function
from psychopy.visual.shape import BaseShapeStim
from psychopy.tools.attributetools import attributeSetter, setAttribute
import numpy as np


class Pie(BaseShapeStim):
"""Creates a pie shape which is a circle with a wedge cut-out.
This shape is sometimes referred to as a Pac-Man shape which is often
used for creating Kanizsa figures. However, the shape can be adapted for
other uses.
Attributes
----------
start, end : float or int
Start and end angles of the filled region of the shape in
degrees. Shapes are filled counter clockwise between the specified
angles.
radius : float or int
Radius of the shape. Avoid using `size` for adjusting figure dimensions
if radius != 0.5 which will result in undefined behavior.
"""
def __init__(self,
win,
radius=.5,
start=0.0,
end=90.0,
edges=32,
units='',
lineWidth=1.5,
lineColor=None,
lineColorSpace='rgb',
fillColor=None,
fillColorSpace='rgb',
pos=(0, 0),
size=1,
ori=0.0,
opacity=1.0,
contrast=1.0,
depth=0,
interpolate=True,
lineRGB=None,
fillRGB=None,
name=None,
autoLog=None,
autoDraw=False,
color=None,
colorSpace=None):

"""
Parameters
----------
win : `~psychopy.visual.Window`
Window this shape is associated with.
radius : float or int
Radius of the shape. Avoid using `size` for adjusting figure
dimensions if radius != 0.5 which will result in undefined behavior.
start, end : float or int
Start and end angles of the filled region of the shape in
degrees. Shapes are filled counter clockwise between the specified
angles.
edges : int
Number of edges to use when drawing the figure. A greater number of
edges will result in smoother curves, but will require more time
to compute.
"""
self.__dict__['radius'] = radius
self.__dict__['edges'] = edges
self.__dict__['start'] = start
self.__dict__['end'] = end

self.vertices = self._calcVertices()

super(Pie, self).__init__(
win,
units=units,
lineWidth=lineWidth,
lineColor=lineColor,
lineColorSpace=lineColorSpace,
fillColor=fillColor,
fillColorSpace=fillColorSpace,
vertices=self.vertices,
closeShape=True,
pos=pos,
size=size,
ori=ori,
opacity=opacity,
contrast=contrast,
depth=depth,
interpolate=interpolate,
lineRGB=lineRGB,
fillRGB=fillRGB,
name=name,
autoLog=autoLog,
autoDraw=autoDraw,
color=color,
colorSpace=colorSpace)

def _calcVertices(self):
"""Calculate the required vertices for the figure.
"""
startRadians = np.radians(self.start)
endRadians = np.radians(self.end)

# get number of steps for vertices
edges = self.__dict__['edges']
steps = np.linspace(startRadians, endRadians, num=edges)

# offset by 1 since the first vertex needs to be at centre
verts = np.zeros((edges + 2, 2), float)
verts[1:-1, 0] = np.sin(steps)
verts[1:-1, 1] = np.cos(steps)

verts *= self.radius

return verts

@attributeSetter
def start(self, value):
"""Start angle of the slice/wedge in degrees (`float` or `int`).
:ref:`Operations <attrib-operations>` supported.
"""
self.__dict__['start'] = value
self.vertices = self._calcVertices()
self.setVertices(self.vertices, log=False)

def setStart(self, start, operation='', log=None):
"""Usually you can use 'stim.attribute = value' syntax instead,
but use this method if you need to suppress the log message
"""
setAttribute(self, 'start', start, log, operation)

@attributeSetter
def end(self, value):
"""End angle of the slice/wedge in degrees (`float` or `int`).
:ref:`Operations <attrib-operations>` supported.
"""
self.__dict__['end'] = value
self.vertices = self._calcVertices()
self.setVertices(self.vertices, log=False)

def setEnd(self, end, operation='', log=None):
"""Usually you can use 'stim.attribute = value' syntax instead,
but use this method if you need to suppress the log message
"""
setAttribute(self, 'end', end, log, operation)

@attributeSetter
def radius(self, value):
"""Radius of the shape in `units` (`float` or `int`).
:ref:`Operations <attrib-operations>` supported.
"""
self.__dict__['radius'] = value
self.vertices = self._calcVertices()
self.setVertices(self.vertices, log=False)

def setRadius(self, end, operation='', log=None):
"""Usually you can use 'stim.attribute = value' syntax instead,
but use this method if you need to suppress the log message
"""
setAttribute(self, 'radius', end, log, operation)

0 comments on commit 584d586

Please sign in to comment.