Skip to content

Commit

Permalink
Rename dir to stimupy
Browse files Browse the repository at this point in the history
  • Loading branch information
JorisVincent committed Feb 20, 2023
1 parent ba3f5de commit e78fa9c
Show file tree
Hide file tree
Showing 74 changed files with 1,577 additions and 1,403 deletions.
6 changes: 0 additions & 6 deletions stimuli/__init__.py

This file was deleted.

1 change: 1 addition & 0 deletions stimupy/__init__.py
@@ -0,0 +1 @@
from stimupy import components, illusions, noises, papers
36 changes: 18 additions & 18 deletions stimuli/components/__init__.py → stimupy/components/__init__.py
@@ -1,9 +1,10 @@
import itertools
import warnings
from copy import deepcopy

import numpy as np

from stimuli.utils import int_factorize, resolution
from stimupy.utils import int_factorize, resolution


def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mean"):
Expand Down Expand Up @@ -74,8 +75,8 @@ def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mea

# Rotated
alpha = [np.cos(np.deg2rad(rotation)), np.sin(np.deg2rad(rotation))]
rotated = alpha[0]*xx + alpha[1]*yy
rotated = alpha[0] * xx + alpha[1] * yy

if origin == "corner":
rotated = rotated - rotated.min()

Expand Down Expand Up @@ -422,28 +423,27 @@ def round_n_phases(n_phases, length, period="either"):
def create_overview():
import numpy as np

import stimuli.components.angulars as angulars
import stimuli.components.checkerboards as checkerboards
import stimuli.components.circulars as circulars
import stimuli.components.edges as edges
import stimuli.components.frames as frames
import stimuli.components.gaussians as gaussians
import stimuli.components.gratings as gratings
import stimuli.components.lines as lines
import stimuli.components.mondrians as mondrians
import stimuli.components.shapes as shapes

import stimupy.components.angulars as angulars
import stimupy.components.checkerboards as checkerboards
import stimupy.components.circulars as circulars
import stimupy.components.edges as edges
import stimupy.components.frames as frames
import stimupy.components.gaussians as gaussians
import stimupy.components.gratings as gratings
import stimupy.components.lines as lines
import stimupy.components.mondrians as mondrians
import stimupy.components.shapes as shapes

p = {
"visual_size": 10,
"ppd": 20,
}
}

p_mondrians = {
"mondrian_positions": ((0,0), (0,5), (1,3), (4,6), (6,1)),
"mondrian_positions": ((0, 0), (0, 5), (1, 3), (4, 6), (6, 1)),
"mondrian_sizes": 3,
"mondrian_intensities": np.random.rand(5),
}
}

# fmt: off
stims = {
Expand Down Expand Up @@ -505,7 +505,7 @@ def create_overview():


def overview(mask=False, save=None):
from stimuli.utils import plot_stimuli
from stimupy.utils import plot_stimuli

stims = create_overview()

Expand Down
28 changes: 17 additions & 11 deletions stimuli/components/angulars.py → stimupy/components/angulars.py
@@ -1,8 +1,8 @@
import numpy as np

from stimuli.components import draw_regions, mask_elements, resolve_grating_params
from stimuli.components.circulars import ring
from stimuli.utils import resolution
from stimupy.components import draw_regions, mask_elements, resolve_grating_params
from stimupy.components.circulars import ring
from stimupy.utils import resolution

__all__ = [
"wedge",
Expand Down Expand Up @@ -52,7 +52,7 @@ def mask_angle(
visual_size=visual_size,
ppd=ppd,
origin=origin,
)
)
stim["wedge_mask"] = stim["mask"]
del stim["mask"]
return stim
Expand Down Expand Up @@ -185,7 +185,7 @@ def mask_segments(
visual_size=visual_size,
ppd=ppd,
origin=origin,
)
)
stim["wedge_mask"] = stim["mask"]
del stim["mask"]
return stim
Expand Down Expand Up @@ -244,7 +244,9 @@ def angular_segments(

# Draw image
stim["img"] = draw_regions(
stim["wedge_mask"], intensities=intensity_segments, intensity_background=intensity_background
stim["wedge_mask"],
intensities=intensity_segments,
intensity_background=intensity_background,
)
return stim

Expand Down Expand Up @@ -296,12 +298,14 @@ def grating(
"""
lst = [visual_size, ppd, shape, frequency, n_segments, segment_width]
if len([x for x in lst if x is not None]) < 3:
raise ValueError("'grating()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_segments', 'segment_width'")
raise ValueError(
"'grating()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_segments', 'segment_width'"
)

# Resolve resolution
shape, visual_size, ppd = resolution.resolve(shape=shape, visual_size=visual_size, ppd=ppd)

if frequency is not None and frequency > 0.5:
raise ValueError("'frequency' in angular grating must be smaller than 0.5")

Expand Down Expand Up @@ -395,8 +399,10 @@ def pinwheel(
"""
lst = [visual_size, ppd, shape, frequency, n_segments, segment_width]
if len([x for x in lst if x is not None]) < 3:
raise ValueError("'pinwheel()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_segments', 'segment_width'")
raise ValueError(
"'pinwheel()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_segments', 'segment_width'"
)
if radius is None:
raise ValueError("pinwheel() missing argument 'radius' which is not 'None'")

Expand Down
@@ -1,14 +1,16 @@
import numpy as np
import warnings
from stimuli.components.gratings import square_wave

import numpy as np

from stimupy.components.gratings import square_wave

__all__ = [
"checkerboard",
]

# TODO: Fix bug that changing rotation, affect check size!


def checkerboard(
visual_size=None,
ppd=None,
Expand Down Expand Up @@ -55,16 +57,18 @@ def checkerboard(
"""
lst = [visual_size, ppd, shape, frequency, board_shape, check_visual_size]
if len([x for x in lst if x is not None]) < 3:
raise ValueError("'checkerboard()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'board_shape', 'check_visual_size'")
raise ValueError(
"'checkerboard()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'board_shape', 'check_visual_size'"
)

if isinstance(frequency, (float, int)) or frequency is None:
frequency = (frequency, frequency)
if isinstance(board_shape, (float, int)) or board_shape is None:
board_shape = (board_shape, board_shape)
if isinstance(check_visual_size, (float, int)) or check_visual_size is None:
check_visual_size = (check_visual_size, check_visual_size)

create_twice = visual_size is None and shape is None

# Create checkerboard by treating it as a plaid
Expand All @@ -81,8 +85,8 @@ def checkerboard(
intensity_bars=intensity_checks,
origin="corner",
round_phase_width=round_phase_width,
)
)

sw2 = square_wave(
visual_size=visual_size,
ppd=ppd,
Expand All @@ -91,13 +95,13 @@ def checkerboard(
n_bars=board_shape[1],
bar_width=check_visual_size[1],
period=period,
rotation=rotation+90,
rotation=rotation + 90,
phase_shift=0,
intensity_bars=intensity_checks,
origin="corner",
round_phase_width=round_phase_width,
)
)

# If neither a visual_size nor a shape was given, each square wave
# grating is always a square. An easy solution is to just recreate
# both gratings with the resolved parameters
Expand All @@ -116,8 +120,8 @@ def checkerboard(
intensity_bars=intensity_checks,
origin="corner",
round_phase_width=round_phase_width,
)
)

sw2 = square_wave(
visual_size=(sw1["visual_size"][0], sw2["visual_size"][1]),
ppd=sw1["ppd"],
Expand All @@ -126,23 +130,25 @@ def checkerboard(
n_bars=board_shape[1],
bar_width=check_visual_size[1],
period=period,
rotation=rotation+90,
rotation=rotation + 90,
phase_shift=0,
intensity_bars=intensity_checks,
origin="corner",
round_phase_width=round_phase_width,
)
)
warnings.filterwarnings("default")

# Add the two square-wave gratings into a checkerboard
img = sw1["img"] + sw2["img"]
img = np.where(img == intensity_checks[0]+intensity_checks[1], intensity_checks[1], intensity_checks[0])

img = np.where(
img == intensity_checks[0] + intensity_checks[1], intensity_checks[1], intensity_checks[0]
)

# Create a mask with target indices for each check
mask = sw1["grating_mask"] + sw2["grating_mask"]*sw1["grating_mask"].max()*10
mask = sw1["grating_mask"] + sw2["grating_mask"] * sw1["grating_mask"].max() * 10
unique_vals = np.unique(mask)
for v in range(len(unique_vals)):
mask[mask == unique_vals[v]] = v+1
mask[mask == unique_vals[v]] = v + 1

stim = {
"img": img,
Expand All @@ -157,5 +163,5 @@ def checkerboard(
"rotation": rotation,
"intensity_checks": intensity_checks,
"edges": (sw1["edges"], sw2["edges"]),
}
}
return stim
56 changes: 23 additions & 33 deletions stimuli/components/circulars.py → stimupy/components/circulars.py
@@ -1,20 +1,14 @@
import copy
import itertools
import warnings

import numpy as np
import scipy.special as sp

from stimuli.components import image_base, mask_elements, resolve_grating_params
from stimuli.utils import resolution
from stimupy.components import image_base, mask_elements, resolve_grating_params
from stimupy.utils import resolution

__all__ = [
"disc_and_rings",
"disc",
"ring",
"annulus",
"grating",
"bessel"
]
__all__ = ["disc_and_rings", "disc", "ring", "annulus", "grating", "bessel"]


def resolve_circular_params(
Expand Down Expand Up @@ -79,7 +73,7 @@ def resolve_circular_params(
frequency=frequency,
period="ignore",
)

# Remove too large radii:
if visual_angle is not None:
if params["edges"][-1] > visual_angle:
Expand Down Expand Up @@ -215,13 +209,7 @@ def disc_and_rings(
visual_size = resolution.validate_visual_size(visual_size)

# Get masks for rings
params = mask_rings(
radii=radii,
shape=shape,
visual_size=visual_size,
ppd=ppd,
origin=origin
)
params = mask_rings(radii=radii, shape=shape, visual_size=visual_size, ppd=ppd, origin=origin)
shape = params["shape"]

# Draw rings
Expand Down Expand Up @@ -297,7 +285,7 @@ def disc(
shape=shape,
origin=origin,
)
stim["ring_mask"] = (stim["ring_mask"]/2).astype(int)
stim["ring_mask"] = (stim["ring_mask"] / 2).astype(int)
return stim


Expand Down Expand Up @@ -417,9 +405,11 @@ def grating(
"""
lst = [visual_size, ppd, shape, frequency, n_rings, ring_width]
if len([x for x in lst if x is not None]) < 3:
raise ValueError("'grating()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_rings', 'ring_width'")

raise ValueError(
"'grating()' needs 3 non-None arguments for resolving from 'visual_size', "
"'ppd', 'shape', 'frequency', 'n_rings', 'ring_width'"
)

# Resolve sizes
try:
shape, visual_size, ppd = resolution.resolve(shape=shape, visual_size=visual_size, ppd=ppd)
Expand All @@ -434,7 +424,7 @@ def grating(
frequency=frequency,
n_rings=n_rings,
ring_width=ring_width,
)
)

# Clean-up params for passing through
stim_params = copy.deepcopy(params)
Expand Down Expand Up @@ -503,8 +493,8 @@ def bessel(
shape=shape,
rotation=0,
origin=origin,
)
)

img = base["radial"] * frequency * 2 * np.pi
img = sp.jv(order, img)
img = (img - img.min()) / (img.max() - img.min())
Expand All @@ -519,22 +509,22 @@ def bessel(
"order": order,
"frequency": frequency,
"intensity_rings": intensity_rings,
}
}
return stim


if __name__ == "__main__":
from stimuli.utils.plotting import plot_stimuli
from stimupy.utils.plotting import plot_stimuli

p = {
"visual_size": (10, 20),
"ppd": 50,
}
}

stims = {
"grating": grating(**p, frequency=2),
"disc_and_rings": disc_and_rings(**p, radii=(1, 2, 3)),
"ring": ring(**p, radii=(1, 2)),
}
}

plot_stimuli(stims, mask=False)

0 comments on commit e78fa9c

Please sign in to comment.