{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "%matplotlib inline"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "\n# Creating a grid of electrodes\n\nThis example shows how to use\n:py:class:`~pulse2percept.implants.ElectrodeGrid`.\n\nMost current electrode arrays arrange their electrodes in a 2D grid.\n\n## Creating a rectangular grid\n\nTo create a rectangular grid, we need to specify:\n\n-  The ``shape`` of the grid, passed as a tuple containing the desired number\n   of rows and columns\n-  The electrode-to-electrode ``spacing`` in microns\n-  The (``x``, ``y``) location of the center of the array\n-  The rotation angle ``rot`` of the grid in degrees, where positive angles\n   rotate all electrodes in the array in a counter-clockwise fashion on the\n   retinal surface.\n\nWe can also specify:\n\n-  A naming convention ``names`` for the rows and columns in the grid.\n   For example, to label rows alphabetically and columns numerically, we would\n   pass a tuple ``('A', '1')``. To label both alphabetically, we would pass\n   ``('A', 'A')``.\n-  An electrode type ``etype``, which must be a subclass of\n   :py:class:`~pulse2percept.implants.Electrode`. By default,\n   :py:class:`~pulse2percept.implants.PointSource` is chosen.\n-  Any additional parameters that should be passed to the\n   :py:class:`~pulse2percept.implants.Electrode` constructor, such as a radius\n   ``r`` for :py:class:`~pulse2percept.implants.DiskElectrode`.\n\nLet's say we want to create a 2x3 rectangular grid of\n:py:class:`~pulse2percept.implants.PointSource` objects, each electrode spaced\n500 microns apart, and the whole grid should be centered over the fovea:\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "from pulse2percept.models import AxonMapModel\nfrom numpy import pi\nfrom pulse2percept.implants import DiskElectrode\nfrom pulse2percept.implants import ElectrodeGrid\n\ngrid = ElectrodeGrid((2, 3), 500)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can access individual electrodes by indexing into ``grid``:\n\nThe first electrode:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "grid[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The first electrode by name:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "grid['A1']"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Accessing the x-coordinate of the first electrode:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "grid[0].x"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "Showing all electrodes:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "grid[:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "We can iterate over all electrodes as if we were dealing with a dictionary:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "for name, electrode in grid.electrodes.items():\n    print(name, electrode)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "To make a grid of :py:class:`~pulse2percept.implants.DiskElectrode` objects,\nwe need to explicitly specify the electrode type (``etype``) and the radius\nto use (``r``):\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "# 11x13 grid, 100-um disk electrodes spaced 500um apart:\ndisk_grid = ElectrodeGrid((11, 13), 500, etype=DiskElectrode, r=100)\n\ndisk_grid[:]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<div class=\"alert alert-info\"><h4>Note</h4><p>You can also specify a list of radii, one value for each electrode in\n    the grid.</p></div>\n\nWe can visualize the grid by using its ``plot`` method:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "disk_grid.plot()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Creating a hexagonal grid\n\nTo create a hexagonal grid instead, all we need to do is change the grid type\nfrom 'rect' (default) to 'hex':\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "hex_grid = ElectrodeGrid((11, 13), 500, type='hex', etype=DiskElectrode, r=100)\n\nhex_grid.plot()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "The following example centers the grid on (x,y) = (-600um, 200 um),\nz=150um away from the retinal surface, and rotates it clockwise by 45 degrees\n(note the minus sign):\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "offset_grid = ElectrodeGrid((11, 13), 500, type='hex', x=-600, y=200, z=150,\n                            rot=-45, etype=DiskElectrode, r=100)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<div class=\"alert alert-info\"><h4>Note</h4><p>Clockwise/counter-clockwise rotations refer to rotations on the retinal\n    surface (that is, as if seen on a fundus photograph).</p></div>\n\nWe can also plot the grid on top of a map of retinal nerve fiber bundles:\n\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "collapsed": false
      },
      "outputs": [],
      "source": [
        "AxonMapModel().plot()\noffset_grid.plot()"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.7.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}