pulse2percept.implants.electrode_arrays

ElectrodeArray, ElectrodeGrid

Classes

ElectrodeArray(electrodes)

Electrode array

ElectrodeGrid(shape, spacing[, x, y, z, ...])

2D grid of electrodes

class pulse2percept.implants.electrode_arrays.ElectrodeArray(electrodes)[source]

Electrode array

A collection of Electrode objects.

Parameters:

electrodes (array-like) –

Either a single Electrode object or a dict, list, or NumPy array thereof. The keys of the dict will serve as electrode names. Otherwise electrodes will be indexed 0..N.

Note

If you pass multiple electrodes in a dictionary, the keys of the dictionary will automatically be sorted. Thus the original order of electrodes might not be preserved.

Examples

Electrode array made from a single DiskElectrode:

>>> from pulse2percept.implants import ElectrodeArray, DiskElectrode
>>> earray = ElectrodeArray(DiskElectrode(0, 0, 0, 100))
>>> earray.electrodes  
OrderedDict([(0,
              DiskElectrode(activated=True, name=None, r=100..., x=0..., y=0...,
              z=0...))])

Electrode array made from a single DiskElectrode with name ‘A1’:

>>> from pulse2percept.implants import ElectrodeArray, DiskElectrode
>>> earray = ElectrodeArray({'A1': DiskElectrode(0, 0, 0, 100)})
>>> earray.electrodes  
OrderedDict([('A1',
              DiskElectrode(activated=True, name=None, r=100..., x=0..., y=0...,
              z=0...))])
coordinate_unit = um[source]

The unit electrode coordinates are stored in, i.e. what the plain numbers returned by coordinates() mean by default.

coordinates(unit=None, electrodes=None)[source]

Positions of the electrodes in the array

The one place to ask an implant where its electrodes are. Code that needs the coordinates in a particular unit says so here, instead of reading electrode.x and knowing that electrodes happen to store microns.

Added in version 0.10.0.

Parameters:
  • unit (Unit, optional) – Length unit to express the coordinates in. If None, they are returned as they are stored (microns).

  • electrodes (optional) –

    Which electrodes to return. Three things name a single electrode, looked up as earray[...] looks one up: a name, an index into the flattened array, and a (row, col) pair on an ElectrodeGrid. Anything else iterable – a list, an array, or the ElectrodeNames a stimulus reports – is a collection, taken in the order given. If None, every electrode in the array, in array order.

    A model passes stim.electrodes here: a stimulus need not name every electrode of the implant, and need not name them in array order, so the coordinates it wants are a reordered subset.

Returns:

coords – One [x, y, z] row per electrode – always two-dimensional, so a single-electrode selection comes back as (1, 3). (For one electrode’s position as a flat triple, see coordinates().) An ordinary NumPy array, never a Quantity: this is the boundary a numerical implementation should take the geometry across.

Return type:

(n_electrodes, 3) np.ndarray

Examples

>>> from pulse2percept.implants import ArgusII
>>> from pulse2percept.units import mm
>>> ArgusII().earray.coordinates(mm)[0]
array([-2.5875, -1.4375,  0.    ])
>>> ArgusII().earray.coordinates(electrodes=['F10', 'A1'])
array([[ 2587.5,  1437.5,     0. ],
       [-2587.5, -1437.5,     0. ]])
add_electrode(name, electrode)[source]

Add an electrode to the array

Parameters:
  • name (int|str|...) – Electrode name or index

  • electrode (implants.Electrode) – An Electrode object, such as a PointSource or a DiskElectrode.

remove_electrode(name)[source]

Remove an electrode from the array

Parameter

name: int|str|…

Electrode name or index

plot(annotate=False, autoscale=True, ax=None, color_stim=None, cmap='OrRd')[source]

Plot the electrode array

Parameters:
  • annotate (bool, optional) – Flag whether to label electrodes in the implant.

  • autoscale (bool, optional) – Whether to adjust the x,y limits of the plot to fit the implant

  • ax (matplotlib.axes._subplots.AxesSubplot, optional) – A Matplotlib axes object. If None, will either use the current axes (if exists) or create a new Axes object.

  • color_stim (pulse2percept.stimuli.Stimulus, or None) – If provided, colors the earray based on the stimulus amplitudes

  • cmap (str) – Matplotlib colormap to use for stimulus coloring.

Returns:

ax – Returns the axis object of the plot

Return type:

matplotlib.axes.Axes

property electrodes

Return all electrode names and objects in the electrode array

Internally, electrodes are stored in an ordered dictionary. You can iterate over different electrodes in the array as follows:

for name, electrode in earray.electrodes.items():
    print(name, electrode)

You can access an individual electrode by indexing directly into the electrode array object, e.g. earray['A1'] or earray[0].

property electrode_names

Return a list of all electrode names in the array

property electrode_objects

Return a list of all electrode objects in the array

class pulse2percept.implants.electrode_arrays.ElectrodeGrid(shape, spacing, x=0, y=0, z=0, rot=0, names=('A', '1'), type='rect', orientation='horizontal', etype=<class 'pulse2percept.implants.electrodes.PointSource'>, **kwargs)[source]

2D grid of electrodes

Parameters:
  • shape ((rows, cols)) – A tuple containing the number of rows x columns in the grid

  • spacing (double or (x_spacing, y_spacing)) – Electrode-to-electrode spacing in microns. Must be either a tuple specifying the spacing in x and y directions or a float (assuming the same spacing in x and y). If a tuple is specified for a horizontal hex grid, x_spacing will define the electrode-to-electrode distance, and y_spacing will define the vertical distance between adjacent hexagon centers. In a vertical hex grid, the order is reversed.

  • type ({'rect', 'hex'}, optional) – Grid type (‘rect’: rectangular, ‘hex’: hexagonal).

  • orientation ({'horizontal', 'vertical'}, optional) – In a hex grid, ‘horizontal’ orientation will shift every other row to the right, whereas ‘vertical’ will shift every other column up.

  • x/y/z (double) – 3D location (um) of the center of the grid. The coordinate system is centered over the fovea. Positive x values move the electrode into the nasal retina. Positive y values move the electrode into the superior retina. Positive z values move the electrode away from the retina into the vitreous humor (sometimes called electrode-retina distance).

  • rot (double, optional) – Rotation of the grid in degrees (positive angle: counter-clockwise rotation on the retinal surface). A plain angle, not a unitful one: dva means visual angle, which is a different thing.

  • names ((name_rows, name_cols), each of which either 'A' or '1') –

    Naming convention for rows and columns, respectively. If ‘A’, rows or columns will be labeled alphabetically: A-Z, AA-AZ, BA-BZ, CA-CZ, etc. ‘-A’ will reverse the order. If ‘1’, rows or columns will be labeled numerically. ‘-1’ will reverse. Letters will always precede numbers in electrode names. For example (‘1’, ‘A’) will number rows numerically and columns alphabetically; first row: ‘A1’, ‘B1’, ‘C1’, NOT ‘1A’, ‘1B’, ‘1C’.

    The default, ('A', '1'), is the same convention that ElectrodeNames uses to name the pixels of an ImageStimulus, and is generated by it. The other combinations exist to reproduce the naming of specific published implants and are not otherwise recommended.

    Alternatively, pass a list or NumPy array with one name per electrode to name them all explicitly. On a grid with exactly two electrodes the two readings collide, and only something that could be a scheme is read as one: names=('A', '1') gives ‘A1’, ‘A2’, whereas names=('C1', '4') names the two electrodes ‘C1’ and ‘4’. Pass a list (names=['A', '1']) to name two electrodes ‘A’ and ‘1’.

    Changed in version 0.10.0: On a grid with exactly two electrodes, ('A', '1') now yields ‘A1’, ‘A2’ (was: ‘A’, ‘1’), consistent with every other shape.

  • etype (Electrode, optional) – A valid Electrode class. By default, PointSource is used.

  • **kwargs – Any additional arguments that should be passed to the Electrode constructor, such as radius r for DiskElectrode. See examples below.

Notes

  • spacing, x, y, z and r may be given as plain numbers of microns or as unitful quantities, and may be mixed freely: spacing=(0.5 * mm, 600 * um) and z=[0 * um, 0.1 * mm, ...] both work. Any other electrode keyword is normalized by the electrode class it is passed to. See pulse2percept.units.

Examples

A hexagonal electrode grid with 3 rows and 4 columns, made of disk electrodes with 10um radius spaced 20um apart, centered at (10, 20)um, and located 500um away from the retinal surface, with names like this:

A1 A2 A3 A4 B1 B2 B3 B4 C1 C2 C3 C4
>>> from pulse2percept.implants import ElectrodeGrid, DiskElectrode
>>> ElectrodeGrid((3, 4), 20, x=10, y=20, z=500, names=('A', '1'), r=10,
...               type='hex', etype=DiskElectrode) 
ElectrodeGrid(rot=0, shape=(3, 4), spacing=20, type='hex')

A rectangular electrode grid with 2 rows and 4 columns, made of disk electrodes with 10um radius spaced 20um apart, centered at (10, 20)um, and located 500um away from the retinal surface, with names like this:

A1 A2 A3 A4 B1 B2 B3 B4
>>> from pulse2percept.implants import ElectrodeGrid, DiskElectrode
>>> ElectrodeGrid((2, 4), 20, x=10, y=20, z=500, names=('A', '1'), r=10,
...               type='rect', etype=DiskElectrode) 
ElectrodeGrid(rot=0, shape=(2, 4), spacing=20, type='rect')

There are three ways to access (e.g.) the last electrode in the grid, either by name (grid['C3']), by row/column index (grid[2, 2]), or by index into the flattened array (grid[8]):

>>> from pulse2percept.implants import ElectrodeGrid
>>> grid = ElectrodeGrid((3, 3), 20, names=('A', '1'))
>>> grid['C3']  
PointSource(activated=True, name='C3', x=20..., y=20...,
            z=0...)
>>> grid['C3'] == grid[8] == grid[2, 2]
True

You can also access multiple electrodes at the same time by passing a list of indices/names (it’s ok to mix-and-match):

>>> from pulse2percept.implants import ElectrodeGrid, DiskElectrode
>>> grid = ElectrodeGrid((3, 3), 20, etype=DiskElectrode, r=10)
>>> grid[['A1', 1, (0, 2)]]  
[DiskElectrode(activated=True, name='A1', r=10..., x=-20.0,
               y=-20.0, z=0...),
 DiskElectrode(activated=True, name='A2', r=10..., x=0.0,
               y=-20.0, z=0...),
 DiskElectrode(activated=True, name='A3', r=10..., x=20.0,
               y=-20.0, z=0...)]
add_electrode(name, electrode)[source]

Add an electrode to the array

Parameters:
  • name (int|str|...) – Electrode name or index

  • electrode (implants.Electrode) – An Electrode object, such as a PointSource or a DiskElectrode.

coordinate_unit = um[source]

The unit electrode coordinates are stored in, i.e. what the plain numbers returned by coordinates() mean by default.

coordinates(unit=None, electrodes=None)[source]

Positions of the electrodes in the array

The one place to ask an implant where its electrodes are. Code that needs the coordinates in a particular unit says so here, instead of reading electrode.x and knowing that electrodes happen to store microns.

Added in version 0.10.0.

Parameters:
  • unit (Unit, optional) – Length unit to express the coordinates in. If None, they are returned as they are stored (microns).

  • electrodes (optional) –

    Which electrodes to return. Three things name a single electrode, looked up as earray[...] looks one up: a name, an index into the flattened array, and a (row, col) pair on an ElectrodeGrid. Anything else iterable – a list, an array, or the ElectrodeNames a stimulus reports – is a collection, taken in the order given. If None, every electrode in the array, in array order.

    A model passes stim.electrodes here: a stimulus need not name every electrode of the implant, and need not name them in array order, so the coordinates it wants are a reordered subset.

Returns:

coords – One [x, y, z] row per electrode – always two-dimensional, so a single-electrode selection comes back as (1, 3). (For one electrode’s position as a flat triple, see coordinates().) An ordinary NumPy array, never a Quantity: this is the boundary a numerical implementation should take the geometry across.

Return type:

(n_electrodes, 3) np.ndarray

Examples

>>> from pulse2percept.implants import ArgusII
>>> from pulse2percept.units import mm
>>> ArgusII().earray.coordinates(mm)[0]
array([-2.5875, -1.4375,  0.    ])
>>> ArgusII().earray.coordinates(electrodes=['F10', 'A1'])
array([[ 2587.5,  1437.5,     0. ],
       [-2587.5, -1437.5,     0. ]])
property electrode_names

Return a list of all electrode names in the array

property electrode_objects

Return a list of all electrode objects in the array

property electrodes

Return all electrode names and objects in the electrode array

Internally, electrodes are stored in an ordered dictionary. You can iterate over different electrodes in the array as follows:

for name, electrode in earray.electrodes.items():
    print(name, electrode)

You can access an individual electrode by indexing directly into the electrode array object, e.g. earray['A1'] or earray[0].

plot(annotate=False, autoscale=True, ax=None, color_stim=None, cmap='OrRd')[source]

Plot the electrode array

Parameters:
  • annotate (bool, optional) – Flag whether to label electrodes in the implant.

  • autoscale (bool, optional) – Whether to adjust the x,y limits of the plot to fit the implant

  • ax (matplotlib.axes._subplots.AxesSubplot, optional) – A Matplotlib axes object. If None, will either use the current axes (if exists) or create a new Axes object.

  • color_stim (pulse2percept.stimuli.Stimulus, or None) – If provided, colors the earray based on the stimulus amplitudes

  • cmap (str) – Matplotlib colormap to use for stimulus coloring.

Returns:

ax – Returns the axis object of the plot

Return type:

matplotlib.axes.Axes

remove_electrode(name)[source]

Remove an electrode from the array

Parameter

name: int|str|…

Electrode name or index