How stimupy is organized#

Broadly, stimupy functions currently fall into the following categories, which are also the toplevel submodules of stimupy:

  • visual stimulus components, such as shapes, wave / gratings, Gaussians, lines

  • visual noise textures, of different kinds,

  • parameterized visual stimuli

    • Gabors, plaids, edges, Mondrians,

    • a variety of so-called illusions (e.g. Simultaneous Brightness Contrast, White’s illusion, Hermann grid, Ponzo illusion), and many more

  • exact replications of stimuli previously published (e.g. ModelFest) as described in their respective papers

  • utility functions for stimulus import, export, manipulation (e.g. contrast, size), or plotting

components vs. stimuli#

There is no objective way to differentiate components from stimuli. In principle, every component could be considered a stimulus. The distinctions we make in stimupy are: firstly, that the components are “atomic” in a sense and hence underlie multiple different stimuli; secondly, most stimuli contain target(s) – a region of special scientific interest –, and come with a target_mask that indicates these targets.

Submodules#

The overall structure of stimupy is further subdivided into many submodules. These submodules are organized along scientific interest, history, convention, etc., rather than engineering. Thus, you will find a stimulus in a submodule with stimuli that either look similar or that are related to each other, rather than with stimuli that it shares components or code with (although these two criteria can overlap, of course).

Moreover, the submodules all have pluralized names, e.g., sbcs for Simultaneous Brightness ContrastS, cubes for Cube illusionS. This is in part to avoid namespace conflicts, i.e. from stimupy.stimuli import cubes uniquely identifies the cubes submodule, where from stimupy.stimuli.cubes import cube uniquely identifies the cubes.cube function. In addition, it also serves to indicate that for a given “stimulus”, there may be multiple functions, see next section.

Multiple alternative stimulus functions#

All roads lead to Rome, and many ways lead to the same stimulus. For some stimuli provided by stimupy, there are multiple ways to generate a specific stimulus. Typically, these different ways are informed by visual and geometric interpretations.

A good example of this is the Todorovic Illusion, which one can interpret as having a rectangular target that is partially occluded by some “covers” OR as having a cross-shaped target with adjoining squares. For a single stimulus parameterization, these two conceptions may produce perfectly identical images (see fig, top). However, when changing parameters, you would expect different behavior from the stimulus function dependent on your conception/interpretation of the stimulus (see fig, bottom).

from stimupy.stimuli import todorovics
from stimupy.utils import plot_stimuli

resolution = {"visual_size": 5, "ppd": 10}

stims = {
    "cross, covers_size=1" : todorovics.cross(**resolution,     cross_size=2,  cross_thickness=1, covers_size=1),
    "rect, covers_size=1"  : todorovics.rectangle(**resolution, target_size=2, covers_offset=1,   covers_size=1),
    "cross, covers_size=.5": todorovics.cross(**resolution,     cross_size=2,  cross_thickness=1, covers_size=0.5),
    "rect, covers_size=.5" : todorovics.rectangle(**resolution, target_size=2, covers_offset=1,   covers_size=0.5),
}

plot_stimuli(stims)
../_images/b2097ba55737e9d59e40afedfd7073b8b7157c27f45a6e747fbdf697278902ad.png

Fig. 1 todorovics.cross() (left) and .rectangle() (right) can produce identical images (top) for some parameterizations, but have different behavior for others (bottom)#

The easiest way to find out how the different functions differ in their behavior, is to interactively explore their parameters using the demos.

Even for those stimuli for which we currently have only have one implementation, (e.g., the Ponzo illusion) we could see other alternatives, and the modular structure of stimupy is designed to make additing these straightforward.