class SquareImplant(ProsthesisSystem):
    def __init__(self,
                 e_num_side,
                 e_radius,
                 spacing=None,
                 side_size=None,
                 stim=None,
                 eye='RE',
                 name=None):
        """
            e_num_side : the number of electrodes in the squares implant's side
            e_radius   : the radius of each electrode in the square implant [microns]
            spacing    : the spacing between to electrodes in the squares implant's [microns]
            side_size  : the size of the squares implant's side in [microns]
            stim       : stimuli signal for each electrode [one dimensional array]
            eye        : the eye where it is implanted ['RE', 'LE']
            name       : name of the implant [string]
        """

        # if there is no name assigned the derive it from the desired characteristics of the implant
        if name is None:
            self.name = f"e_num_side={e_num_side}-e_radius={e_radius}-spacing={spacing}-side_size={side_size}"
        else:
            self.name = name

        # if side size is set the derive the spacing between each electrod from it
        if side_size is not None:
            spacing = (side_size - 2 * e_radius) / (e_num_side - 1)
        elif spacing is None:
            raise Exception(
                "Provide a 'spacing' or 'side_size' parameter in microns")

        if spacing < 2 * e_radius:
            warnings.warn(
                'Either the electrode radius (e_radius) is too big or the side size (side_size) '
                + 'is too small and there is electrode overlap',
                stacklevel=2)

        self.earray = ElectrodeGrid((e_num_side, e_num_side),
                                    x=0,
                                    y=0,
                                    z=0,
                                    rot=0,
                                    r=e_radius,
                                    spacing=spacing,
                                    etype=DiskElectrode,
                                    names=('A', '1'))
        self.stim = stim
        self.eye = eye

    # plot implant on an axon map
    def plot_on_axon_map(self,
                         annotate_implant=False,
                         annotate_quadrants=True,
                         ax=None):
        if ax is None:
            _, ax = plt.subplots(figsize=(10, 10))
        AxonMapModel().plot(annotate=annotate_quadrants, ax=ax)
        self.earray.plot(annotate=annotate_implant, ax=ax)
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[:]

##############################################################################
# .. 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:

disk_grid.plot()

##############################################################################
# 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()

##############################################################################
# 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