Note
Click here to download the full example code
Creating a grid of electrodes¶
This example shows how to use
ElectrodeGrid
.
Most current electrode arrays arrange their electrodes in a 2D grid.
Creating a rectangular grid¶
To create a rectangular grid, we need to specify:
- The
shape
of the grid, passed as a tuple containing the desired number of rows and columns - The electrode-to-electrode
spacing
in microns - The (
x
,y
) location of the center of the array - The rotation angle
rot
of the grid in degrees, where positive angles rotate all electrodes in the array in a counter-clockwise fashion on the retinal surface.
We can also specify:
- A naming convention
names
for the rows and columns in the grid. For example, to label rows alphabetically and columns numerically, we would pass a tuple('A', '1')
. To label both alphabetically, we would pass('A', 'A')
. - An electrode type
etype
, which must be a subclass ofElectrode
. By default,PointSource
is chosen. - Any additional parameters that should be passed to the
Electrode
constructor, such as a radiusr
forDiskElectrode
.
Let’s say we want to create a 2x3 rectangular grid of
PointSource
objects, each electrode spaced
500 microns apart, and the whole grid should be centered over the fovea:
from pulse2percept.implants import ElectrodeGrid
grid = ElectrodeGrid((2, 3), 500)
We can access individual electrodes by indexing into grid
:
The first electrode:
grid[0]
Out:
PointSource(x=-500.0, y=-250.0, z=0.0)
The first electrode by name:
grid['A1']
Out:
PointSource(x=-500.0, y=-250.0, z=0.0)
Accessing the x-coordinate of the first electrode:
grid[0].x
Out:
-500.0
Showing all electrodes:
grid[:]
Out:
[PointSource(x=-500.0, y=-250.0, z=0.0), PointSource(x=0.0, y=-250.0, z=0.0), PointSource(x=500.0, y=-250.0, z=0.0), PointSource(x=-500.0, y=250.0, z=0.0), PointSource(x=0.0, y=250.0, z=0.0), PointSource(x=500.0, y=250.0, z=0.0)]
We can iterate over all electrodes as if we were dealing with a dictionary:
Out:
A1 PointSource(x=-500.0, y=-250.0, z=0.0)
A2 PointSource(x=0.0, y=-250.0, z=0.0)
A3 PointSource(x=500.0, y=-250.0, z=0.0)
B1 PointSource(x=-500.0, y=250.0, z=0.0)
B2 PointSource(x=0.0, y=250.0, z=0.0)
B3 PointSource(x=500.0, y=250.0, z=0.0)
To make a grid of DiskElectrode
objects,
we need to explicitly specify the electrode type (etype
) and the radius
to use (r
):
from pulse2percept.implants import DiskElectrode
# 11x13 grid, 100-um disk electrodes spaced 500um apart:
disk_grid = ElectrodeGrid((11, 13), 500, etype=DiskElectrode, r=100)
disk_grid[:]
Out:
[DiskElectrode(r=100.0, x=-3000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=-2500.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=-2000.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=-1500.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=-1000.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=-500.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=0.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=500.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=1000.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=1500.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=2000.0, z=0.0), DiskElectrode(r=100.0, x=-3000.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=-2500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=-2000.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=-1500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=-1000.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=-500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=0.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=1000.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=1500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=2000.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=2500.0, y=2500.0, z=0.0), DiskElectrode(r=100.0, x=3000.0, y=2500.0, z=0.0)]
Note
You can also specify a list of radii, one value for each electrode in the grid.
We can visualize the grid by using its plot
method:
Out:
<AxesSubplot:xlabel='x (microns)', ylabel='y (microns)'>
Creating a hexagonal grid¶
To create a hexagonal grid instead, all we need to do is change the grid type from ‘rect’ (default) to ‘hex’:
hex_grid = ElectrodeGrid((11, 13), 500, type='hex', etype=DiskElectrode, r=100)
hex_grid.plot()
Out:
<AxesSubplot:xlabel='x (microns)', ylabel='y (microns)'>
The following example centers the grid on (x,y) = (-600um, 200 um), z=150um away from the retinal surface, and rotates it clockwise by 45 degrees (note the minus sign):
from numpy import pi
offset_grid = ElectrodeGrid((11, 13), 500, type='hex', x=-600, y=200, z=150,
rot=-45, etype=DiskElectrode, r=100)
Note
Clockwise/counter-clockwise rotations refer to rotations on the retinal surface (that is, as if seen on a fundus photograph).
We can also plot the grid on top of a map of retinal nerve fiber bundles:
from pulse2percept.models import AxonMapModel
AxonMapModel().plot()
offset_grid.plot()
Out:
<AxesSubplot:xlabel='x (microns)', ylabel='y (microns)'>
Total running time of the script: ( 0 minutes 1.120 seconds)