pulse2percept.stimuli.base

Stimulus, ImageStimulus

Functions

merge_time_axes(data, time[, merge_tolerance])

Merge time axes

unique_time_points(time[, merge_tolerance])

Sorted union of several time axes, merging points that coincide

Classes

Stimulus(source[, electrodes, time, ...])

A stimulus is comprised of a labeled 2D NumPy array that contains the data, where the rows denote electrodes and the columns denote points in time.

pulse2percept.stimuli.base.unique_time_points(time, merge_tolerance=1e-06)[source]

Sorted union of several time axes, merging points that coincide

Two stimuli that sample the same instant rarely agree on it to the last bit, because each accumulated its own way there. An exact np.unique would keep both copies, leaving the merged axis with a pair of points far closer together than the DT that separates two genuinely distinct ones.

Parameters:
  • time (list of 1-D arrays) – The time axes to merge.

  • merge_tolerance (float, optional) – Two time points closer together than this (or than the accumulated drift at their magnitude, whichever is coarser) are the same point.

Returns:

  • t_sorted (1-D array) – The sorted, concatenated time points.

  • starts_group (1-D bool array) – Which entries of t_sorted start a new group, i.e. which of them survive the merge.

  • order (1-D int array) – The permutation that sorted the concatenated axes.

pulse2percept.stimuli.base.merge_time_axes(data, time, merge_tolerance=1e-06)[source]

Merge time axes

When a collection of source types is passed, it is possible that they have different time axes (e.g., different time steps, or a different stimulus duration). In this case, we need to merge all time axes into a single, coherent one. This is expensive, because of interpolation.

Parameters:
  • data (list) – List of numpy.ndarray’s containing data points associated with time axes.

  • time (list) – List of numpy.ndarray’s containing time points to merge

  • merge_tolerance (float) – Absolute tolerance used when collecting unique time points from the time axes. Two time points that are closer together than this (or closer than float32 can resolve at their own magnitude, whichever is coarser) are treated as the same point.

  • Returns – Tuple of: list of new data points (linearly interpolated from merged time axis), list of new merged time axis.

  • -------

class pulse2percept.stimuli.base.Stimulus(source, electrodes=None, time=None, metadata=None, compress=False)[source]

A stimulus is comprised of a labeled 2D NumPy array that contains the data, where the rows denote electrodes and the columns denote points in time. A stimulus can be created from a variety of source types (e.g., scalars, lists, NumPy arrays, and dictionaries).

See also

  • Basic Concepts > Electrical Stimuli <topics-stimuli>

Added in version 0.6.

Parameters:
  • source (source type) –

    A valid source type is one of the following:

    • Scalar value: interpreted as the current amplitude delivered to a single electrode (no time component).

    • NumPy array:
      • Nx1 array: interpreted as N current amplitudes delivered to N electrodes (no time component).

      • NxM array: interpreted as N electrodes each receiving M current amplitudes in time.

    In addition, you can also pass a collection of source types. Each element must be a valid source type for a single electrode (e.g., scalar, 1-D array, Stimulus).

    • List or tuple: List elements will be assigned to electrodes in order.

    • Dictionary: Dictionary keys are used to address electrodes by name.

  • electrodes (int, string or list thereof; optional) –

    Optionally, you can provide your own electrode names. If none are given, electrode names will be extracted from the source type (e.g., the keys from a dictionary). If a scalar or NumPy array is passed, electrode names will be numbered 0..N.

    Note

    The number of electrode names provided must match the number of electrodes extracted from the source type (i.e., N).

  • time (int, float or list thereof; optional) –

    Optionally, you can provide the time points of the source data. If none are given, time steps will be numbered 0..M.

    Note

    The number of time points provided must match the number of time points extracted from the source type (i.e., M). Stimuli created from scalars or 1-D NumPy arrays will have no time componenet, in which case you cannot provide your own time points.

  • metadata (dict, optional) – Additional stimulus metadata can be stored in a dictionary.

  • compress (bool, optional) –

    If True, will compress the source data in two ways:

    • Remove electrodes with all-zero activation.

    • Retain only the time points at which the stimulus changes.

    For example, in a pulse train, only the signal edges are saved. This drastically reduces the memory footprint of the stimulus.

Notes

  • Depending on the source type, a stimulus might have a time component or not (e.g., scalars: time=None).

  • You can access the stimulus applied to electrode e at time t by directly indexing into Stimulus[e, t]. In this case, t is not a column index but a time point.

  • If the time point is not explicitly stored in the data container, its value will be automatically interpolated from neighboring values.

  • If a requested time point lies outside the range of stored data, the value of its closest end point will be returned.

Examples

Stimulate a single electrode with -13uA:

>>> from pulse2percept.stimuli import Stimulus
>>> stim = Stimulus(-13)

Stimulate ten electrodes with 0uA:

>>> from pulse2percept.stimuli import Stimulus
>>> stim = Stimulus(np.zeros(10))

Provide new electrode names for an existing Stimulus object:

>>> from pulse2percept.stimuli import Stimulus
>>> old_stim = Stimulus([3, 5])
>>> new_stim = Stimulus(old_stim, electrodes=['new0', 'new1'])

Interpolate the stimulus value at some point in time. Here, the stimulus is a single-electrode ramp stimulus (stimulus value == point in time):

>>> from pulse2percept.stimuli import Stimulus
>>> stim = Stimulus(np.arange(10).reshape((1, -1)))
>>> stim[:, 3.45] 
3.45...
compress()[source]

Compress the source data

Returns:

compressed

Return type:

Stimulus

append(other)[source]

Append another stimulus

This method appends another stimulus (with matching electrodes) in time. The combined stimulus duration will be the sum of the two individual stimuli.

Added in version 0.7.

Parameters:

other (Stimulus) – Another stimulus with matching electrodes.

Returns:

comb – A combined stimulus with the same number of electrodes and new stimulus duration equal to the sum of the two individual stimuli.

Return type:

Stimulus

remove(electrodes)[source]

Remove electrode(s)

Removes the stimulus of a certain electrode or list of electrodes.

Added in version 0.8.

Parameters:

electrodes (int, string, or list of int/str) – The item(s) to remove from the stimulus. Can either be an electrode index, electrode name, or a list thereof.

plot(electrodes=None, time=None, fmt='k-', ax=None)[source]

Plot the stimulus

Added in version 0.7.

Parameters:
  • electrodes (int, string, or list thereof; optional, default: None) – The electrodes for which to plot the stimulus. If None, all electrodes are plotted.

  • time ((t_min, t_max) tuple, slice, or list of exact time points) – The time points at which to plot the stimulus. Specify a range of time points with a tuple or a slice, or specify the exact time points to interpolate. If None, all time points are plotted.

  • fmt (str, optional, default: 'k-') – A Matplotlib format string; e.g., ‘ro’ for red circles.

  • ax (matplotlib.axes.Axes or list thereof; optional, default: None) – A Matplotlib Axes object or a list thereof (one per electrode to plot). If None, a new Axes object will be created.

Returns:

axes – Returns one matplotlib.axes.Axes per electrode

Return type:

matplotlib.axes.Axes or np.ndarray of them

property data

Stimulus data container A 2-D NumPy array that contains the stimulus data, where the rows denote electrodes and the columns denote points in time.

property shape

Data container shape

property unit

The unit data is expressed in

Microamps for an electrical stimulus, dimensionless for the gray levels of an ImageStimulus or VideoStimulus.

Read-only. The canonical storage unit is fixed so that models, safety checks and Cython kernels can rely on it; ask for another unit with values().

Added in version 0.10.0.

property time_unit

The unit time is expressed in (milliseconds)

Added in version 0.10.0.

property quantity

The stimulus data, with its unit attached

Added in version 0.10.0.

Examples

>>> from pulse2percept.stimuli import Stimulus
>>> from pulse2percept.units import uA
>>> Stimulus([500, 1000] * uA).quantity
[[ 500.]
 [1000.]] uA
property time_quantity

The stimulus time axis with its unit attached, or None

Added in version 0.10.0.

values(unit=None)[source]

The stimulus data, expressed in unit

Added in version 0.10.0.

Parameters:

unit (Unit, optional) – The unit to express the data in. Must be compatible with unit. If None, the stimulus’ own unit is used and data is returned as it is stored.

Returns:

values – An ordinary NumPy array, never a Quantity. This is the boundary a numerical implementation should take its data across.

Return type:

np.ndarray

Examples

>>> from pulse2percept.stimuli import Stimulus
>>> from pulse2percept.units import uA, mA
>>> Stimulus([500, 1000] * uA).values(mA)
array([[0.5],
       [1. ]], dtype=float32)
times(unit=None)[source]

The stimulus time axis, expressed in unit

Added in version 0.10.0.

Parameters:

unit (Unit, optional) – The unit to express the time axis in. If None, time is returned as it is stored (milliseconds).

Returns:

times – An ordinary NumPy array, or None if the stimulus has no time component.

Return type:

np.ndarray or None

property electrodes

Electrode names A list of electrode names, corresponding to the rows in the data container.

property time

Time steps A list of time steps, corresponding to the columns in the data container.

property is_compressed

Flag indicating whether the stimulus has been compressed

Read-only: the flag is maintained by compress. Assigning to it raises an AttributeError.

property dt

Sampling time step (ms)

Defines the duration of the signal edge transitions.

Added in version 0.7.

property is_charge_balanced

Flag indicating whether the stimulus is charge-balanced

A stimulus with a time component is considered charge-balanced if its net current is smaller than 10 pico Amps. For the whole stimulus to be charge-balanced, every electrode must be charge-balanced as well.

Returns None if the stimulus is not a current at all: the gray levels of an ImageStimulus integrate to a number like any others, but that number is not a charge and asking whether it is zero answers nothing. Note that this is “not applicable”, not “unbalanced” – it is safe_mode that turns the question into an error, since a safety system genuinely cannot do its job on a stimulus that is not electrical.

Changed in version 0.10.0: Returns None for a stimulus that is not measured in units of current (was: integrated the values anyway).

property duration

Stimulus duration (ms)