From 3d47a1df98300ac7141f4bcd4bd450dd15e4ebef Mon Sep 17 00:00:00 2001 From: matko031 Date: Wed, 18 Aug 2021 17:51:23 +0200 Subject: [PATCH] added docstrings and updated READMEs --- README.md | 16 +- stimuli/illusions/README.md | 21 ++- stimuli/illusions/benary_cross.py | 29 +++- stimuli/illusions/bullseye.py | 37 ++++- .../checkerboard_contrast_contrast.py | 31 ++-- stimuli/illusions/checkerboard_sbc.py | 46 ++++-- stimuli/illusions/cube.py | 42 +++-- stimuli/illusions/disc_and_ring.py | 1 - stimuli/illusions/dungeon.py | 29 ++-- stimuli/illusions/grating.py | 31 ++-- stimuli/illusions/grating_induction.py | 31 ++++ stimuli/illusions/rings.py | 34 ++-- stimuli/illusions/sbc.py | 22 ++- stimuli/illusions/square_wave.py | 42 +++-- stimuli/illusions/todorovic.py | 29 ++-- stimuli/illusions/whites.py | 145 ++++++++++++++++-- 16 files changed, 448 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index 3fc17675..a661b298 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Stimuli Contains submodules for -- creating different stimuli used in lightness perception ([lightness](src/lightness/README.md)) -- creating different brightness illusions ([illusions](src/illusions/README.md)) +- creating different brightness illusions ([illusions](stimuli/illusions/)) +- replicating illusions in certain published papers ([papers](stimuli/papers/)) - creating 2D patterns or renderings of 3D checkerboards with transparent -layers covering part of the image ([transparency](src/transparency/README.md)) -- various functions that calculate contrast metrics ([contrast_metrics](src/contrest_metrics/README.md)) +layers covering part of the image ([transparency](stimuli/transparency/)) +- various functions that calculate contrast metrics ([contrast_metrics](stimuli/contrest_metrics/)) - some helper functions for padding, resizing, computing Munsell values, and -converting pixel values to degrees of visual angle ([utils](src/utils/README.md#utils)) -- (creating different random and deterministic textures ([texture](src/texture/README.md)) [yet to be fixed]) +converting pixel values to degrees of visual angle ([utils](stimuli/utils/)) +- (creating different random and deterministic textures ([texture](stimuli/texture/)) [yet to be fixed]) -For details, please refer to the source directory (src/), the respective subdirectories and the docstrings. +For details, please refer to the source directory (stimuli/), the respective subdirectories and the docstrings. ## Dependencies - Required: numpy, matplotlib, PIL @@ -34,7 +34,7 @@ This makes changes to files immediately usable, rather than having to reinstall the package after every change. ## Importing -To use in your own code, import the modules. See READMEs in src/ for example usages. +To use in your own code, import the modules. See READMEs in stimuli/ for example usages. ```python from stimuli import lightness from stimuli import illusions diff --git a/stimuli/illusions/README.md b/stimuli/illusions/README.md index 5faa4c4b..018e8286 100644 --- a/stimuli/illusions/README.md +++ b/stimuli/illusions/README.md @@ -1,3 +1,20 @@ -## Brightness Illusions +## Illusions -For example usage, see `/tests/test_brightness_illusions.py`. \ No newline at end of file +This directory contains modules for creating various brightness illusions. +Each module contains a function to create the general version of the illusion with suitable default parameters. +Beside that, in each module one can find the implementations of functions for generating illusions used in published papers. +These functions are the one being called from the modules in `papers` directory. + +An overview of all illusions can be generated by running the `overview.py` module. +Each functions returns a `Stimulus` object. `img` attribute contains a 2D numpy array +representing the illusion and `target_mask` attribute contains an integer mask specifying +the location of target patches inside the illusion. +### Example usage +```python +from stimuli import illusions, utils +import matplotlib.pyplot as plt + +stimulus = illusions.whites.white() +utils.plot_stim(stimulus, mask=True) +plt.show() +``` \ No newline at end of file diff --git a/stimuli/illusions/benary_cross.py b/stimuli/illusions/benary_cross.py index a7aa0981..2f9259ec 100644 --- a/stimuli/illusions/benary_cross.py +++ b/stimuli/illusions/benary_cross.py @@ -9,17 +9,26 @@ def benarys_cross(ppd=10, cross_size=(8,8,8,8), cross_thickness=5, padding=(1,1, Parameters ---------- - cross_size: size of the cross in degrees visual angle in form (top, bottom, left, right) specifying the length of each of the cross' bars - cross_thickness: width of the cross bars in degrees visual angle - padding: 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle - target_size: size of the side of target square in degrees visual angle - back: background value - cross: cross value - target: target value + ppd : int + pixels per degree (visual angle) + cross_size : (float, float, float, float) + size of the cross in degrees visual angle in form (top, bottom, left, right) specifying the length of each of the cross' bars + cross_thickness : float + width of the cross bars in degrees visual angle + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + target_size : float + size of the side of target square in degrees visual angle + back : float + background value + cross : float + cross value + target : float + target value Returns ------- - 2D numpy array + A stimulus object """ @@ -58,6 +67,10 @@ def benarys_cross(ppd=10, cross_size=(8,8,8,8), cross_thickness=5, padding=(1,1, return stim def domijan2015(): + """ + Generates Benary Cross illusion as used in the Domijan 2015 paper. + """ + return illusions.benarys_cross(ppd=10, cross_size=(3,3,3,3), cross_thickness=2.1, padding=(.9,1.0,.9,1.0),target_size=1.1, back=9., cross=1., target=5.) if __name__ == '__main__': diff --git a/stimuli/illusions/bullseye.py b/stimuli/illusions/bullseye.py index c7405413..9820e9fa 100644 --- a/stimuli/illusions/bullseye.py +++ b/stimuli/illusions/bullseye.py @@ -11,16 +11,28 @@ def bullseye_illusion(ppd=10, n_rings=8, ring_width=.5, target_pos_l=0, target_p Parameters ---------- - n_rings: the number of rings - ring_width: width per ring in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - back: value for background - rings: value for grid cells - target: value for target + ppd : int + pixels per degree (visual angle) + n_rings : int + the number of rings + ring_width : float + width per ring in degrees visual angle + target_pos_l : int + specify the target index in the left ring + target_pos_r : int + specify the target index in the right ring + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + back : float + background value + rings : float + value for grid cells + target : float + value for target Returns ------- - 2D numpy array + A stimulus object """ stim1 = ring_pattern(n_rings=n_rings, target_pos_l=target_pos_l, ring_width=ring_width, padding=padding, back=back, rings=rings, target=target, invert_rings=False, double=False) @@ -37,13 +49,24 @@ def bullseye_illusion(ppd=10, n_rings=8, ring_width=.5, target_pos_l=0, target_p return stim def domijan2015(): + """ + Generates Bullseye illusion as used in the Domijan 2015 paper. + """ + img = illusions.bullseye_illusion(n_rings=8, ring_width=.5, target_pos_l=0, target_pos_r=0, padding=(.9,1.0,.9,1.0), back=1., rings=9., target=5.) return img def RHS2007_bullseye_thin(): + """ + Generates Bullseye thin illusion as used in the Robinson, Hammon and de Sa 2007 paper. + """ return illusions.bullseye_illusion(n_rings=8, ring_width=1, padding=(100,100,100,100), back=1., rings=9., target=5.) def RHS2007_bullseye_thick(): + """ + Generates Bullseye thick illusion as used in the Robinson, Hammon and de Sa 2007 paper. + """ + return illusions.bullseye_illusion(n_rings=8, ring_width=1, padding=(50,50,50,50), back=1., rings=9., target=5.) if __name__ == '__main__': diff --git a/stimuli/illusions/checkerboard_contrast_contrast.py b/stimuli/illusions/checkerboard_contrast_contrast.py index 05b29b70..1c6ade7f 100644 --- a/stimuli/illusions/checkerboard_contrast_contrast.py +++ b/stimuli/illusions/checkerboard_contrast_contrast.py @@ -10,18 +10,28 @@ def checkerboard_contrast_contrast_effect(ppd=10, n_checks=8, check_size=1.0, ta Parameters ---------- - n_checks: number of checks per board in each direction - check_size: size of a check in px - target_length: size of the target in # checks - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - check1: a check value - check2: other check value - tau: tau of transparency - alpha: alpha of transparency + ppd : int + pixels per degree (visual angle) + n_checks : int + number of checks per board in each direction + check_size : float + size of a check in degrees visual angle + target_length : int + size of the target in # checks + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + check1 : float + first check value + check2 : float + other check value + tau : float + tau of transparency + alpha : float + alpha of transparency Returns ------- - 2D numpy array + A stimulus object """ check_size_px = degrees_to_pixels(check_size, ppd) @@ -71,6 +81,9 @@ def checkerboard_contrast_contrast_effect(ppd=10, n_checks=8, check_size=1.0, ta def domijan2015(): + """ + Generates checkerboard contrast contrast illusion as used in Domijan 2015 paper. + """ return illusions.checkerboard_contrast_contrast_effect(ppd=10, n_checks=8, check_size=1.0, target_length=4, padding=(.9,1.1,.9,1.1), check1=1., check2=9., tau=5, alpha= .5) diff --git a/stimuli/illusions/checkerboard_sbc.py b/stimuli/illusions/checkerboard_sbc.py index f455e4bf..1eefea02 100644 --- a/stimuli/illusions/checkerboard_sbc.py +++ b/stimuli/illusions/checkerboard_sbc.py @@ -11,19 +11,30 @@ def checkerboard_contrast(ppd=10, board_shape=(8,8), check_size=1.0, target1_coo Parameters ---------- - board shape: number of checks per board in y, x direction - check_size: size of a check in px - target1_coords: check-coordinates of target check 1 - target2_coords: check-coordinates of target check 2 - extend_targets: cross targets instead of single-check targets - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - check1: a check value - check2: other check value - target: target value + ppd : int + pixels per degree (visual angle) + board shape : (int, int) + number of checks per board in y, x direction + check_size : float + size of a check in degrees visual angle + target1_coords : (int, int) + check-coordinates of target check 1 + target2_coords : (int, int) + check-coordinates of target check 2 + extend_targets : bool + cross targets instead of single-check targets + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + check1 : float + first check value + check2 : float + other check value + target: float + target value Returns ------- - + A stimulus object """ check_size_px = degrees_to_pixels(check_size, ppd) @@ -60,6 +71,9 @@ def checkerboard_contrast(ppd=10, board_shape=(8,8), check_size=1.0, target1_coo def domijan2015(): + """ + Generates checkerboard_sbc illusion as used in Domijan 2015 paper. + """ stim = illusions.checkerboard_contrast(ppd=10, board_shape=(8,8), check_size=1.0, target1_coords=(3, 2), target2_coords=(5, 5), extend_targets=False, check1=1., check2=9., target=5.) padding = (.9, 1.1, .9, 1.1) stim.img = pad_img(stim.img, padding, ppd=10, val=5.) @@ -68,6 +82,9 @@ def domijan2015(): def domijan2015_extended(): + """ + Generates checkerboard_sbc extended illusion as used in Domijan 2015 paper. + """ stim = illusions.checkerboard_contrast(ppd=10, board_shape=(8,8), check_size=1.0, target1_coords=(3, 2), target2_coords=(5, 5), extend_targets=True, check1=1., check2=9., target=5.) padding = (.9, 1.1, .9, 1.1) stim.img = pad_img(stim.img, padding, ppd=10, val=5.) @@ -76,6 +93,9 @@ def domijan2015_extended(): def RHS2007_Checkerboard016(): + """ + Generates checkerboard 0.16 illusion as used in Robinson, Hammon and de Sa 2007 paper. + """ total_height, total_width, ppd = (32,) * 3 height_checks, width_checks = 40, 102 check_height = 32/102 @@ -93,6 +113,9 @@ def RHS2007_Checkerboard016(): def RHS2007_Checkerboard0938(): + """ + Generates checkerboard 0.94 illusion as used in Robinson, Hammon and de Sa 2007 paper. + """ total_height, total_width, ppd = (32,) * 3 height_checks, width_checks = 7, 25 check_height = 0.938 @@ -109,6 +132,9 @@ def RHS2007_Checkerboard0938(): def RHS2007_Checkerboard209(): + """ + Generates checkerboard 2.1 illusion as used in Robinson, Hammon and de Sa 2007 paper. + """ total_height, total_width, ppd = (32,) * 3 height_checks, width_checks = 3, 10 check_height = 2.09 diff --git a/stimuli/illusions/cube.py b/stimuli/illusions/cube.py index 02a0a20e..6e73b758 100644 --- a/stimuli/illusions/cube.py +++ b/stimuli/illusions/cube.py @@ -6,27 +6,43 @@ def cube_illusion(ppd=10, n_cells=5, target_length=2, cell_long=1.5, cell_short=1.0, corner_cell_width=1.8, corner_cell_height=1.8, cell_spacing=.5, padding=(1.0,1.0,1.0,1.0), occlusion_overlap=(.7,.7,.7,.7), back=0., grid=1., target=.5, double=True): - """ Cube illusion (Agostini & Galmonte, 2002) Parameters ---------- - n_cells: the number of square cells (not counting background) per dimension - target_length: length in # cells per edge of the square - cell_long: long side of a cell in px - cell_short: short side of a cell in px - cell_spacing: distance between two cells in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - occlusion_overlap: 4-valued tuple specifying how many px the big central square overlaps the cells on (top, bottom, left, right - back: value for background - grid: value for grid cells - target: value for target - double: whether to return the full illusion with two grids side-by-side (inverting back and grid values) + ppd : int + pixels per degree (visual angle) + n_cells : int + the number of square cells (not counting background) per dimension + target_length : int + length in # cells per edge of the square + cell_long : float + long side of a cell in degrees visual angle + cell_short : float + short side of a cell in degrees visual angle + corner_cell_width : float + width of the corner cells in degrees visual angle + corner_cell_height: float + height of the corner cells in degrees visual angle + cell_spacing : float + distance between two cells in degrees visual angle + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + occlusion_overlap : (float, float, float, float) + 4-valued tuple specifying how much the big central square overlaps the cells on (top, bottom, left, right) in degrees visual angle + back : float + value for background + grid : float + value for grid cells + target : float + value for target + double : bool + whether to return the full illusion with two grids side-by-side (inverting back and grid values) Returns ------- - 2D numpy array + A stimulus object """ cell_long_px, cell_short_px = degrees_to_pixels(cell_long, ppd), degrees_to_pixels(cell_short, ppd) corner_cell_width_px, corner_cell_height_px = degrees_to_pixels(corner_cell_width, ppd), degrees_to_pixels(corner_cell_height, ppd) diff --git a/stimuli/illusions/disc_and_ring.py b/stimuli/illusions/disc_and_ring.py index 8d86a0e9..7af20522 100644 --- a/stimuli/illusions/disc_and_ring.py +++ b/stimuli/illusions/disc_and_ring.py @@ -7,7 +7,6 @@ def disc_and_ring( shape=(10, 10), radii=(4, 2), values=(0.5, 1), bg=0, ppd=30, ssf=5 ): # TODO: the parameters aren't analogous to the other stimuli - # TODO: figure out defeault parameters that create something that makes sense """ Create a disc and ring stimulus with an arbitrary number of rings. diff --git a/stimuli/illusions/dungeon.py b/stimuli/illusions/dungeon.py index c81bc24c..c9c697dc 100644 --- a/stimuli/illusions/dungeon.py +++ b/stimuli/illusions/dungeon.py @@ -9,19 +9,28 @@ def dungeon_illusion(ppd=10, n_cells=5, target_radius=1, cell_size=1.0, padding= Parameters ---------- - n_cells: the number of square cells (not counting background) per dimension - target_radius: the "Manhattan radius" of the diamond target in # cells - cell_size: size per cell in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - back: value for background - grid: value for grid cells - target: value for target - double: whether to return the full illusion with two grids side-by-side (inverting back and grid values) - shift: number of x,y pixels to shift all the squares by. Top left corner is 0,0 + ppd : int + pixels per degree (visual angle) + n_cells : int + the number of square cells (not counting background) per dimension + target_radius : int + the "Manhattan radius" of the diamond target in # cells + cell_size : float + size per cell in degrees visual angle + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + back : float + value for background + grid : float + value for grid cells + target : float + value for target + double : bool + whether to return the full illusion with two grids side-by-side (inverting back and grid values) Returns ------- - 2D numpy array + A stimulus object """ cell_size_px = degrees_to_pixels(cell_size, ppd) diff --git a/stimuli/illusions/grating.py b/stimuli/illusions/grating.py index f2a24019..5114abe7 100644 --- a/stimuli/illusions/grating.py +++ b/stimuli/illusions/grating.py @@ -9,19 +9,30 @@ def grating_illusion(ppd=10, n_bars=5, target_length=2, bar_width=1.0, bar_heigh Parameters ---------- - n_bars: the number of vertical bars - target_length: # bars that make up the target - bar_width: width of bar in px - bar_height: height of bar in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - back: value for background - grid: value for grid cells - target: value for target - double: whether to return the full illusion with two grids side-by-side (inverting back and grid values) + ppd : int + pixels per degree (visual angle) + n_bars : int + the number of vertical bars + target_length : int + #bars that make up the target + bar_width : float + width of bar in degrees visual angle + bar_height : float + height of bar in degrees visual angle + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + back : float + value for background + grid : float + value for grid cells + target : float + value for target + double : bool + whether to return the full illusion with two grids side-by-side (inverting back and grid values) Returns ------- - 2D numpy array + A stimulus object """ bar_height_px, bar_width_px = degrees_to_pixels(bar_height, ppd), degrees_to_pixels(bar_width, ppd) diff --git a/stimuli/illusions/grating_induction.py b/stimuli/illusions/grating_induction.py index a688c091..e129396b 100644 --- a/stimuli/illusions/grating_induction.py +++ b/stimuli/illusions/grating_induction.py @@ -8,6 +8,37 @@ # Grating induction # ################################### def grating_illusion(shape=(10,10), ppd=40, frequency=0.5, target_height=0.5, blur=None, high=1., low=0., target=.5, start='low', period='ignore', padding=(2,2,2,2)): + """ + Grating induction illusions + + Parameters + ---------- + shape : (float, float) + Shape of the illusion in degrees visual angle + ppd : int + pixels per degree (visual angle) + frequency : float + frequency of the grid in cycles per degree visual angle + target_height : float + height of the target in degrees visual angle + blur : float + amount of blur to apply + high : float + value of the bright stripes + low : float + value of the dark stripes + start : string in ['low','high'] + whether to start with a bright or a low stripes + period : string in ['ignore', 'full', 'half'] + see square_wave.py for details about this + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + + Returns + ------- + A stimulus object + """ + if blur == None: blur = shape[0]/2 diff --git a/stimuli/illusions/rings.py b/stimuli/illusions/rings.py index 3e8edbbe..3a603acf 100644 --- a/stimuli/illusions/rings.py +++ b/stimuli/illusions/rings.py @@ -9,20 +9,32 @@ def ring_pattern(ppd=10, n_rings=8, target_pos_l=4, target_pos_r=3, ring_width=. Parameters ---------- - n_rings: the number of rings - target_pos_l: the "index" of the target ring on the left half - target_pos_r: the "index" of the targetring on the right half - ring_width: width per ring in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - back: value for background - rings: value for grid cells - target: value for target - invert_rings: inverts ordering of rings and background - double: whether to return the full illusion with two grids side-by-side (inverting back and grid values) + ppd : int + pixels per degree (visual angle) + n_rings : int + the number of rings + target_pos_l : int + the "index" of the target ring on the left half + target_pos_r : int + the "index" of the target ring on the right half + ring_width : float + width per ring in degrees visual angle + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + back : float + value for background + rings : float + value for grid cells + target : float + value for target + invert_rings : bool + inverts ordering of rings and background + double : bool + whether to return the full illusion with two grids side-by-side (inverting back and grid values) Returns ------- - 2D numpy array + A stimulus object """ ring_width_px = degrees_to_pixels(ring_width, ppd) diff --git a/stimuli/illusions/sbc.py b/stimuli/illusions/sbc.py index f811590a..232f0fcf 100644 --- a/stimuli/illusions/sbc.py +++ b/stimuli/illusions/sbc.py @@ -10,16 +10,24 @@ def simultaneous_brightness_contrast(ppd=10, target_shape=(5,5), padding=(2,2,2, Parameters ---------- - shape: shape of the stimulus in degrees visual angle (height,width) - target_shape: target shape in degrees visual angle (height, width) - padding: 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle - left: left background value - right: right background value - target: target value + ppd : int + pixels per degree (visual angle) + target shape : (float, float) + target shape in degrees visual angle (height, width) + padding : (float, float, float, float) + 4-valued tuple specifying outer padding (top, bottom, left, right) in degrees visual angle + inner_padding: + 4-valued tuple specifying inner padding (top, bottom, left, right) in degrees visual angle + left : float + left background value + right : float + right background value + target : float + target value Returns ------- - 2d numpy array + A stimulus object """ target_height, target_width = target_shape diff --git a/stimuli/illusions/square_wave.py b/stimuli/illusions/square_wave.py index 4710aeee..4cf004de 100644 --- a/stimuli/illusions/square_wave.py +++ b/stimuli/illusions/square_wave.py @@ -9,32 +9,28 @@ def square_wave(shape=(10,10), ppd=10, frequency=1, high=1.0, low=0.0, period='i Parameters ---------- - shape : tuple of 2 numbers - The shape of the stimulus in degrees of visual angle. (y,x) - ppd : number - the number of pixels in one degree of visual angle - high: float - value of the bright pixels - low: float - value of the dark pixels - frequency : number - the spatial frequency of the wave in cycles per degree - - period : string in ['ignore', 'full', 'half'] (optional) - specifies if the period of the wave is taken into account when - determining exact stimulus dimensions. - 'ignore' simply converts degrees to pixels - 'full' rounds down to guarantee a full period - 'half' adds a half period to the size 'full' would yield. - Default is 'ignore'. - start : string in ['high', 'low'] (optional) - specifies if the wave starts with a high or low value. Default is - 'high'. + shape : (float, float) + The shape of the stimulus in degrees of visual angle. (y,x) + ppd : int + pixels per degree (visual angle) + high : float + value of the bright pixels + low : float + value of the dark pixels + frequency : float + the spatial frequency of the wave in cycles per degree + period : string in ['ignore', 'full', 'half'] + specifies if the period of the wave is taken into account when determining exact stimulus dimensions. + 'ignore' simply converts degrees to pixels + 'full' rounds down to guarantee a full period + 'half' adds a half period to the size 'full' would yield. + Default is 'ignore'. + start : string in ['high', 'low'] + specifies if the wave starts with a high or low value. Default is 'high'. Returns ------- - stim : ndarray (2D) - the square wave stimulus + (2D ndarray, pixels_per_cycle) """ diff --git a/stimuli/illusions/todorovic.py b/stimuli/illusions/todorovic.py index f394aed5..3aec28de 100644 --- a/stimuli/illusions/todorovic.py +++ b/stimuli/illusions/todorovic.py @@ -12,19 +12,30 @@ def todorovic_illusion(target_shape=(4,4), ppd=10, covers_shape=(2.5, 2.5), spac Parameters ---------- - target_padding: tuple specifying distance of the target edge from (top, bottom, left,right) edge of the stimulus - squares_size: tuple specifying (height, width) of the four squares covering the target in px - spacing: spacing between grid cells (i.e target cross bar thickness) in px - padding: 4-valued tuple specifying padding (top, bottom, left, right) in px - back: value for background - grid: value for grid cells - target: value for target - double: whether to return the full illusion with two grids side-by-side (inverting back and grid values) + target_shape : (float, float) + The shape of the target in degrees of visual angle (height, width) + ppd : int + pixels per degree (visual angle) + covers_shape : (float, float) + The shape of the covers in degrees of visual angle (height, width) + spacing : (float, float, float, float) + Spacing between the covers in the form of (top, bottom, left, right). + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + back : float + value for background + grid : float + value for grid cells + target : float + value for target + double: bool + whether to return the full illusion with two grids side-by-side Returns ------- - + A stimulus object """ + target_height, target_width = target_shape target_height_px, target_width_px = degrees_to_pixels(target_shape, ppd) diff --git a/stimuli/illusions/whites.py b/stimuli/illusions/whites.py index 8d60a533..8330b07b 100644 --- a/stimuli/illusions/whites.py +++ b/stimuli/illusions/whites.py @@ -8,6 +8,43 @@ def white(shape=(10,10), ppd=50, frequency=0.4, high=1.0, low=0.0, target=0.5, period='ignore', start='low', target_indices=(2,5), target_height=None, targets_offset=0, orientation = 'horizontal', padding=(2,2,2,2)): + """ + Whites's illusion + + Parameters + ---------- + shape : (float, float) + The shape of the illustion in degrees of visual angle (height, width) + ppd : int + pixels per degree (visual angle) + frequency : float + frequency of the grid in cycles per degree visual angle + high : float + value of the bright stripes + low : float + value of the dark stripes + target : float + value for target + period : string in ['ignore', 'full', 'half'] + see square_wave.py for details about this + start : string in ['low','high'] + whether to start with a bright or a low stripes + target_indices : (int, ) + indices of the stripes where the target(s) will be placed. There will be as many targets as indices specified. + target_height : float + height of the target in degrees visual angle. If it's None, the target will be 1/3 of the illusion height + targets_offset : int + Vertical offset of the target in pixels + orientation : string in ['horizontal', 'vertical'] + orientation of the illusion + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + + Returns + ------- + A stimulus object + """ + height_px, width_px = degrees_to_pixels(shape, ppd) if target_height is None: @@ -45,7 +82,32 @@ def white(shape=(10,10), ppd=50, frequency=0.4, high=1.0, low=0.0, target=0.5, p def circular_white(radius=5, ppd=50, frequency=1, high=1., low=0., target=.5, target_indices=(2,6), start='low', padding=(2,2,2,2)): """ - frequency: cycles per degree + Circular Whites's illusion + + Parameters + ---------- + radius : float + radius of the circle in degrees visual angle + ppd : int + pixels per degree (visual angle) + frequency : float + frequency of the circles in cycles per degree visual angle + high : float + value of the bright stripes + low : float + value of the dark stripes + target : float + value for target + target_indices : (int, ) + indices of the stripes where the target(s) will be placed. There will be as many targets as indices specified. + start : string in ['low','high'] + whether to start with a bright or a low stripes + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + + Returns + ---------- + A stimulus object """ height, width = (degrees_to_pixels(radius*2, ppd),)*2 @@ -83,14 +145,40 @@ def circular_white(radius=5, ppd=50, frequency=1, high=1., low=0., target=.5, ta def wheel_of_fortune_white(radius=10, ppd=50, n_cycles=5, target_width=0.7, target_indices=None, target_start=0.5, angle_shift=0, high=1.0, low=0., target=.5, start='high', padding=(1,1,1,1)): #TODO: make this faster - - # Inputs: - # - n_parts: number of black and white parts within circle (int), it - # should be even numbered to avoid asymmetry - # - target_width: relative width of the targets between 0 and 1 (float) - - # Decide on resolution for the grid. - # The lower the resolution, the worse the wheel of fortune will look + """ + Wheel of fortune Whites's illusion + + Parameters + ---------- + radius : float + radius of the circle in degrees visual angle + ppd : int + pixels per degree (visual angle) + n_cycles : int + number of full grid cycles in the circle + target_width : float in interval [0,1] + width of the target, 1 means target goes from center all the way to the edge of the circle + target_indices : (int, ) + indices of the stripes where the target(s) will be placed + target_start : float in interval [0,1] + specify where the target starts relative to the radius + angle_shift : float + rotate the circle for specified amount of radians + high : float + value of the bright stripes + low : float + value of the dark stripes + target : float + value for target + start : string in ['low','high'] + whether to start with a bright or a low stripes + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + + Returns + ---------- + A stimulus object + """ n_parts=n_cycles*2 @@ -170,7 +258,44 @@ def wheel_of_fortune_white(radius=10, ppd=50, n_cycles=5, target_width=0.7, targ def white_anderson(shape=(5,5), ppd=40, frequency=2, height_bars=1, height_horizontal_top=1, target_height=1, target_indices_top=(5,), target_offsets_top=(0.5,), target_indices_bottom=(12,), target_offsets_bottom=(-0.5,), high=1., low=0., target=.5, top='low', padding=(1,1,1,1)): - + """ + Anderson's white illusion + + Parameters + ---------- + shape : (float, float) + The shape of the illustion in degrees of visual angle (height, width) + ppd : int + pixels per degree (visual angle) + frequency : float + frequency of the grid in cycles per degree visual angle + height_bars : float + height of the bars in degrees visual angle + target_height : float + height of the target in degrees visual angle. If it's None, the target will be 1/3 of the illusion height + target_indices_top : (int, ) + indices of the stripes where the target(s) will be placed. If None, two targets are put on (0, n_parts // 2). + target_offsets_top : (float, ) + vertical offsets of targets in the top + target_indices_bottom : (int, ) + indices of the stripes where the target(s) will be placed. If None, two targets are put on (0, n_parts // 2). + target_offsets_bottom : (float, ) + vertical offsets of targets in the bottom + high : float + value of the bright stripes + low : float + value of the dark stripes + target : float + value for target + top : string in ['low', 'high'] + specify whether the top should be bright or dark + padding : (float, float, float, float) + 4-valued tuple specifying padding (top, bottom, left, right) in degrees visual angle + + Returns + ------- + A stimulus object + """ height, width = degrees_to_pixels(shape, ppd) pixels_per_cycle = degrees_to_pixels(1. / (frequency*2) , ppd) * 2 height_bars, height_horizontal_top = degrees_to_pixels(height_bars, ppd), degrees_to_pixels(height_horizontal_top, ppd)