Skip to content

Commit

Permalink
Merge pull request #28 from computational-psychology/dev
Browse files Browse the repository at this point in the history
Closing some smaller issues
  • Loading branch information
JorisVincent committed Mar 22, 2023
2 parents c7c2754 + a26defc commit b1dfd47
Show file tree
Hide file tree
Showing 25 changed files with 278 additions and 201 deletions.
2 changes: 1 addition & 1 deletion docs/_templates/autosummary/noises.rst
Expand Up @@ -60,7 +60,7 @@
{% if functions %}
Demos
-----
:doc:`reference/demos/components/{{name}}`
:doc:`../../demos/noises/{{name}}`

Functions
---------
Expand Down
30 changes: 15 additions & 15 deletions docs/reference/demos/components/waves.md
Expand Up @@ -39,7 +39,7 @@ w_height = iw.IntSlider(value=10, min=1, max=20, description="height [deg]")
w_width = iw.IntSlider(value=10, min=1, max=20, description="width [deg]")
w_ppd = iw.IntSlider(value=20, min=1, max=40, description="ppd")
w_base_type = iw.Dropdown(value="horizontal", options=['horizontal','vertical','rotated','radial','cityblock','angular'], description="base_type")
w_distance_metric = iw.Dropdown(value="horizontal", options=['horizontal','vertical','oblique','radial','rectilinear','angular'], description="distance_metric")
w_freq = iw.FloatSlider(value=1, min=0, max=2, description="frequency [cpd]")
w_phase = iw.FloatSlider(value=0, min=0, max=360, description="phase shift [deg]")
w_rot = iw.FloatSlider(value=0, min=0, max=360, description="rotation [deg]")
Expand All @@ -54,7 +54,7 @@ w_mask = iw.ToggleButton(value=False, disabled=False, description="add mask")
# Layout
b_im_size = iw.HBox([w_height, w_width, w_ppd])
b_geometry = iw.HBox([w_base_type, w_freq, w_phase, w_rot])
b_geometry = iw.HBox([w_distance_metric, w_freq, w_phase, w_rot])
b_intensities = iw.HBox([w_int1, w_int2])
b_add = iw.HBox([w_ori, w_period, w_round, w_mask])
ui = iw.VBox([b_im_size, b_geometry, b_intensities, b_add])
Expand All @@ -64,7 +64,7 @@ def show_sine(
height=None,
width=None,
ppd=None,
base_type=None,
distance_metric=None,
rotation=None,
frequency=None,
phase_shift=None,
Expand All @@ -78,7 +78,7 @@ def show_sine(
stim = sine(
visual_size=(height, width),
ppd=ppd,
base_type=base_type,
distance_metric=distance_metric,
rotation=rotation,
frequency=frequency,
phase_shift=phase_shift,
Expand All @@ -96,7 +96,7 @@ out = iw.interactive_output(
"height": w_height,
"width": w_width,
"ppd": w_ppd,
"base_type": w_base_type,
"distance_metric": w_distance_metric,
"rotation": w_rot,
"frequency": w_freq,
"phase_shift": w_phase,
Expand Down Expand Up @@ -124,7 +124,7 @@ w_height = iw.IntSlider(value=10, min=1, max=20, description="height [deg]")
w_width = iw.IntSlider(value=10, min=1, max=20, description="width [deg]")
w_ppd = iw.IntSlider(value=20, min=1, max=40, description="ppd")
w_base_type = iw.Dropdown(value="horizontal", options=['horizontal','vertical','rotated','radial','cityblock','angular'], description="base_type")
w_distance_metric = iw.Dropdown(value="horizontal", options=['horizontal','vertical','oblique','radial','rectilinear','angular'], description="distance_metric")
w_freq = iw.FloatSlider(value=1, min=0, max=2, description="frequency [cpd]")
w_phase = iw.FloatSlider(value=0, min=0, max=360, description="phase shift [deg]")
w_rot = iw.FloatSlider(value=0, min=0, max=360, description="rotation [deg]")
Expand All @@ -139,7 +139,7 @@ w_mask = iw.ToggleButton(value=False, disabled=False, description="add mask")
# Layout
b_im_size = iw.HBox([w_height, w_width, w_ppd])
b_geometry = iw.HBox([w_base_type, w_freq, w_phase, w_rot])
b_geometry = iw.HBox([w_distance_metric, w_freq, w_phase, w_rot])
b_intensities = iw.HBox([w_int1, w_int2])
b_add = iw.HBox([w_ori, w_period, w_round, w_mask])
ui = iw.VBox([b_im_size, b_geometry, b_intensities, b_add])
Expand All @@ -149,7 +149,7 @@ def show_square(
height=None,
width=None,
ppd=None,
base_type=None,
distance_metric=None,
rotation=None,
frequency=None,
phase_shift=None,
Expand All @@ -163,7 +163,7 @@ def show_square(
stim = square(
visual_size=(height, width),
ppd=ppd,
base_type=base_type,
distance_metric=distance_metric,
rotation=rotation,
frequency=frequency,
phase_shift=phase_shift,
Expand All @@ -181,7 +181,7 @@ out = iw.interactive_output(
"height": w_height,
"width": w_width,
"ppd": w_ppd,
"base_type": w_base_type,
"distance_metric": w_distance_metric,
"rotation": w_rot,
"frequency": w_freq,
"phase_shift": w_phase,
Expand Down Expand Up @@ -209,7 +209,7 @@ w_height = iw.IntSlider(value=10, min=1, max=20, description="height [deg]")
w_width = iw.IntSlider(value=10, min=1, max=20, description="width [deg]")
w_ppd = iw.IntSlider(value=20, min=1, max=40, description="ppd")
w_base_type = iw.Dropdown(value="horizontal", options=['horizontal','vertical','rotated','radial','cityblock','angular'], description="base_type")
w_distance_metric = iw.Dropdown(value="horizontal", options=['horizontal','vertical','oblique','radial','rectilinear','angular'], description="distance_metric")
w_freq = iw.FloatSlider(value=0.5, min=0, max=2, description="frequency [cpd]")
w_rot = iw.FloatSlider(value=0, min=0, max=360, description="rotation [deg]")
w_phase = iw.FloatSlider(value=0, min=0, max=360, description="phase shift [deg]")
Expand All @@ -224,7 +224,7 @@ w_mask = iw.ToggleButton(value=False, disabled=False, description="add mask")
# Layout
b_im_size = iw.HBox([w_height, w_width, w_ppd])
b_geometry = iw.HBox([w_base_type, w_freq, w_phase, w_rot])
b_geometry = iw.HBox([w_distance_metric, w_freq, w_phase, w_rot])
b_intensities = iw.HBox([w_int1, w_int2])
b_add = iw.HBox([w_ori, w_period, w_round, w_mask])
ui = iw.VBox([b_im_size, b_geometry, b_intensities, b_add])
Expand All @@ -234,7 +234,7 @@ def show_staircase(
height=None,
width=None,
ppd=None,
base_type=None,
distance_metric=None,
rotation=None,
frequency=None,
phase_shift=None,
Expand All @@ -248,7 +248,7 @@ def show_staircase(
stim = staircase(
visual_size=(height, width),
ppd=ppd,
base_type=base_type,
distance_metric=distance_metric,
rotation=rotation,
frequency=frequency,
phase_shift=phase_shift,
Expand All @@ -266,7 +266,7 @@ out = iw.interactive_output(
"height": w_height,
"width": w_width,
"ppd": w_ppd,
"base_type": w_base_type,
"distance_metric": w_distance_metric,
"rotation": w_rot,
"frequency": w_freq,
"int1": w_int1,
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/demos/stimuli/plaids.md
Expand Up @@ -107,7 +107,7 @@ def show_plaid(
"origin": origin,
"round_phase_width": round_phase_width,
"period": period,
"base_type": "rotated",
"distance_metric": "oblique",
}
p_grating1 = {
Expand Down
4 changes: 2 additions & 2 deletions docs/reference/demos/stimuli/waves.md
Expand Up @@ -126,9 +126,9 @@ display(ui, out)

## Square, radial

## Sine, cityblock
## Sine, rectilinear

## Square, cityblock
## Square, rectilinear

## Sine, angular

Expand Down
78 changes: 50 additions & 28 deletions stimupy/components/__init__.py
Expand Up @@ -5,6 +5,8 @@
from stimupy.utils import resolution

__all__ = [
"overview",
"plot_overview",
"image_base",
"draw_regions",
"mask_elements",
Expand Down Expand Up @@ -46,14 +48,14 @@ def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mea
"x", "y" : single axes
"horizontal", "vertical" : numpy.ndarray of shape, with distance from origin,
in deg. visual angle, at each pixel
"rotated" : numpy.ndarray of shape, with rotated distance from origin,
"oblique" : numpy.ndarray of shape, with oblique distance from origin,
in deg. visual angle, at each pixel
"radial" : numpyn.ndarray of shape, with radius from origin,
in deg. visual angle, at each pixel
"angular" : numpy.ndarray of shape, with angle relative to 3 o'clock,
in rad, at each pixel
"cityblock" : numpy.ndarray of shape, with cityblock distance from origin,
in deg. visual angle ,at each pixel
"rectilinear" : numpy.ndarray of shape, with rectilinear/cityblock/Manhattan distance from origin,
in deg. visual angle, at each pixel
"""

# Resolve resolution
Expand All @@ -77,8 +79,8 @@ def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mea
# Linear distance image bases
xx, yy = np.meshgrid(x, y)

# City-block distance (frames)
cityblock = np.maximum(np.abs(xx), np.abs(yy))
# Rectilinear distance (frames)
rectilinear = np.maximum(np.abs(xx), np.abs(yy))

# Radial distance
radial = np.sqrt(xx**2 + yy**2)
Expand All @@ -88,12 +90,12 @@ def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mea
angular -= np.deg2rad(rotation + 90)
angular %= 2 * np.pi

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

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

return {
"visual_size": visual_size,
Expand All @@ -104,15 +106,15 @@ def image_base(visual_size=None, shape=None, ppd=None, rotation=0.0, origin="mea
"y": y,
"horizontal": xx,
"vertical": yy,
"rotated": rotated,
"cityblock": cityblock,
"oblique": oblique,
"rectilinear": rectilinear,
"radial": radial,
"angular": angular,
}


def mask_elements(
orientation,
distance_metric,
edges,
shape=None,
visual_size=None,
Expand All @@ -124,7 +126,7 @@ def mask_elements(
Parameters
----------
orientation : any of keys in stimupy.components.image_base()
distance_metric : any of keys in stimupy.components.image_base()
which dimension to mask over
edges : Sequence[Number]
upper-limit of each consecutive elements
Expand Down Expand Up @@ -152,7 +154,7 @@ def mask_elements(
base = image_base(
shape=shape, visual_size=visual_size, ppd=ppd, rotation=rotation, origin=origin
)
distances = base[orientation]
distances = base[distance_metric]
distances = np.round(distances, 8)

# Mark elements with integer idx-value
Expand All @@ -164,7 +166,7 @@ def mask_elements(
return {
"mask": mask,
"edges": edges,
"orientation": orientation,
"distance_metric": distance_metric,
"rotation": base["rotation"],
"shape": base["shape"],
"visual_size": base["visual_size"],
Expand Down Expand Up @@ -208,17 +210,16 @@ def draw_regions(mask, intensities, intensity_background=0.5):
return img


from . import angulars, edges, frames, gaussians, lines, radials, shapes, waves
from stimupy.components import angulars, edges, frames, gaussians, lines, radials, shapes, waves


def create_overview():
"""
Create dictionary with examples from all stimulus-components
def overview(skip=False):
"""Generate example stimuli from this module
Returns
-------
stims : dict
dict with all stimuli containing individual stimulus dicts.
dict[str, dict]
Dict mapping names to individual stimulus dicts
"""

p = {
Expand All @@ -227,7 +228,7 @@ def create_overview():
}

# fmt: off
stims = {
stimuli = {
# angulars
"wedge": angulars.wedge(**p, width=30, radius=3),
"angular_grating": angulars.grating(**p, n_segments=8),
Expand Down Expand Up @@ -262,12 +263,31 @@ def create_overview():
}
# fmt: on

return stims
# stimuli = {}
# for stimmodule_name in __all__:
# if stimmodule_name in ["overview", "plot_overview"]:
# pass

# print(f"Generating stimuli from {stimmodule_name}")
# # Get a reference to the actual module
# stimmodule = globals()[stimmodule_name]
# try:
# stims = stimmodule.overview()

def overview(mask=False, save=None, extent_key="shape"):
"""
Plot overview with examples from all stimulus-components
# # Accumulate
# stimuli.update(stims)
# except NotImplementedError as e:
# if not skip:
# raise e
# # Skip stimuli that aren't implemented
# print("-- not implemented")
# pass

return stimuli


def plot_overview(mask=False, save=None, extent_key="shape"):
"""Plot overview of examples in this module (and submodules)
Parameters
----------
Expand All @@ -284,7 +304,9 @@ def overview(mask=False, save=None, extent_key="shape"):
"""
from stimupy.utils import plot_stimuli

stims = create_overview()
stims = overview(skip=True)
plot_stimuli(stims, mask=mask, extent_key=extent_key, save=save)


# Plotting
plot_stimuli(stims, mask=mask, save=save, extent_key=extent_key)
if __name__ == "__main__":
plot_overview()
4 changes: 2 additions & 2 deletions stimupy/components/angulars.py
Expand Up @@ -46,7 +46,7 @@ def mask_angle(
"""
stim = mask_elements(
edges=np.deg2rad(angles),
orientation="angular",
distance_metric="angular",
rotation=rotation,
shape=shape,
visual_size=visual_size,
Expand Down Expand Up @@ -178,7 +178,7 @@ def mask_segments(
and additional keys containing stimulus parameters
"""
stim = mask_elements(
orientation="angular",
distance_metric="angular",
edges=np.deg2rad(edges),
rotation=rotation,
shape=shape,
Expand Down
7 changes: 4 additions & 3 deletions stimupy/components/edges.py
@@ -1,4 +1,5 @@
import copy

import numpy as np

from stimupy.components import gaussians, image_base
Expand Down Expand Up @@ -49,9 +50,9 @@ def step_edge(
)

img = np.ones(shape) * intensity_edges[0]
img = np.where(base["rotated"] < base["rotated"].mean(), img, intensity_edges[1])
img = np.where(base["oblique"] < base["oblique"].mean(), img, intensity_edges[1])
mask = np.ones(shape)
mask = np.where(base["rotated"] < base["rotated"].mean(), mask, 2)
mask = np.where(base["oblique"] < base["oblique"].mean(), mask, 2)

stim = {
"img": img,
Expand Down Expand Up @@ -198,7 +199,7 @@ def cornsweet_edge(
if ramp_width > max(base["visual_size"]) / 2:
raise ValueError("ramp_width is too large")

dist = np.round(base["rotated"] / ramp_width, 6)
dist = np.round(base["oblique"] / ramp_width, 6)
d1 = copy.deepcopy(dist)
d2 = copy.deepcopy(dist) * (-1)
d1[d1 < 0] = -1
Expand Down
2 changes: 1 addition & 1 deletion stimupy/components/frames.py
Expand Up @@ -38,7 +38,7 @@ def mask_frames(
and additional keys containing stimulus parameters
"""
stim = mask_elements(
orientation="cityblock",
distance_metric="rectilinear",
edges=edges,
rotation=0.0,
shape=shape,
Expand Down

0 comments on commit b1dfd47

Please sign in to comment.