# -*- coding: utf-8 -*-
#
# connplotter_tutorial.py
#
# This file is part of NEST.
#
# Copyright (C) 2004 The NEST Initiative
#
# NEST is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# NEST is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with NEST.  If not, see <http://www.gnu.org/licenses/>.

# !========================
# ! ConnPlotter: A Tutorial
# !========================
# !
# ! :Author: Hans Ekkehard Plesser
# ! :Institution: Norwegian University of Life Sciences, Simula
# !               Research Laboratory, RIKEN Brain Sciences Institute
# ! :Version: 0.7
# ! :Date: 1 December 2009
# ! :Copyright: Hans Ekkehard Plesser
# ! :License: Creative Commons Attribution-Noncommercial-Share Alike License
# !           v 3.0
# !
# ! :Note: For best results, you should run this script with PyReport by
# !        Gael Varoquaux, available from
# !        http://gael-varoquaux.info/computers/pyreport/
# !
# !        Please set using_pyreport to True if you want to run the
# !        script through pyreport. Otherwise, figures will not be captured
# !        correctly.

using_pyreport = False

# ! Introduction
# !=============
# ! This tutorial gives a brief introduction to the ConnPlotter
# ! toolbox.  It is by no means complete.

# ! Avoid interactive backend when using pyreport
if using_pyreport:
    import matplotlib

    matplotlib.use("Agg")

# ! Import pylab to call pylab.show() so that pyreport
# ! can capture figures created. Must come before import
# ! ConnPlotter so we get the correct show().
import pylab

# ! If not using pyreport, disable pylab.show() until we reach end of script
if not using_pyreport:
    pylab_show = pylab.show

    def nop(s=None):
        pass

    pylab.show = nop

# ! Import ConnPlotter and its examples
import ConnPlotter as cpl
import ConnPlotter.examples as ex

# ! Turn of warnings about resized figure windows
import warnings

warnings.simplefilter("ignore")


# ! Define a helper function to show LaTeX tables on the fly
def showTextTable(connPattern, fileTrunk):
    """
    Shows a Table of Connectivity as textual table.

    Arguments:
    connPattern  ConnectionPattern instance
    fileTrunk    Eventual PNG image will be fileTrunk.png
    """
    import subprocess as subp  # to call LaTeX etc
    import os  # to remove files
    # Write to LaTeX file so we get a nice textual representation
    # We want a complete LaTeX document, so we set ``standalone``
    # to ``True``.
    connPattern.toLaTeX(file=fileTrunk + '.tex', standalone=True,
                        enumerate=True)
    # Create PDF, crop, and convert to PNG
    try:
        devnull = open('/dev/null', 'w')
        subp.call(['pdflatex', fileTrunk], stdout=devnull, stderr=subp.STDOUT)
        # need wrapper, since pdfcrop does not begin with #!
        subp.call(['pdfcrop ' + fileTrunk + '.pdf ' + fileTrunk + '-crop.pdf'],
                  shell=True,
                  stdout=devnull, stderr=subp.STDOUT)
        devnull.close()
        os.rename(fileTrunk + '-crop.pdf', fileTrunk + '.pdf')
        for suffix in ('.tex', '-crop.pdf', '.png', '.aux', '.log'):
            if os.path.exists(fileTrunk + suffix):
                os.remove(fileTrunk + suffix)
    except:
        raise Exception('Could not create PDF Table.')


# ! Simple network
# ! ==============

# ! This is a simple network with two layers A and B; layer B has two
# ! populations, E and I. On the NEST side, we use only synapse type
# ! ``static_synapse``. ConnPlotter then infers that synapses with positive
# ! weights should have type ``exc``, those with negative weight type ``inh``.
# !  Those two types are know to ConnPlotter.

# ! Obtain layer, connection and model list from the example set
s_layer, s_conn, s_model = ex.simple()

# ! Create Connection Pattern representation
s_cp = cpl.ConnectionPattern(s_layer, s_conn)

# ! Show pattern as textual table (we cheat a little and include PDF directly)
showTextTable(s_cp, 'simple_tt')
# $ \centerline{\includegraphics{simple_tt.pdf}}

# ! Show pattern in full detail
# ! ---------------------------

# ! A separate patch is shown for each pair of populations.
# !
# !  - Rows represent senders, columns targets.
# !  - Layer names are given to the left/above, population names to the right
# !    and below.
# !  - Excitatory synapses shown in blue, inhibitory in red.
# !  - Each patch has its own color scale.
s_cp.plot()
pylab.show()

# ! Let us take a look at what this connection pattern table shows:
# !
# ! - The left column, with header "A", is empty: The "A" layer receives
# !   no input.
# ! - The right column shows input to layer "B"
# !
# !   * The top row, labeled "A", has two patches in the "B" column:
# !
# !     + The left patch shows relatively focused input to the "E" population
# !       in layer "B" (first row of "Connectivity" table).
# !     + The right patch shows wider input to the "I" population in layer
# !       "B" (second row of "Connectivity" table).
# !     + Patches are red, indicating excitatory connections.
# !     + In both cases, mask are circular, and the product of connection
# !       weight and probability is independent of the distance between sender
# !       and target neuron.
# !
# !   * The grey rectangle to the bottom right shows all connections from
# !     layer "B" populations to layer "B" populations. It is subdivided into
# !     two rows and two columns:
# !
# !     + Left column: inputs to the "E" population.
# !     + Right column: inputs to the "I" population.
# !     + Top row: projections from the "E" population.
# !     + Bottom row: projections from the "I" population.
# !     + There is only one type of synapse for each sender-target pair,
# !       so there is only a single patch per pair.
# !     + Patches in the top row, from population "E" show excitatory
# !        connections, thus they are red.
# !     + Patches in the bottom row, from population "I" show inhibitory
# !       connections, thus they are blue.
# !     + The patches in detail are:
# !
# !       - **E to E** (top-left, row 3+4 in table): two rectangular
# !          projections at 90 degrees.
# !       - **E to I** (top-right, row 5 in table): narrow gaussian projection.
# !       - **I to E** (bottom-left, row 6 in table): wider gaussian projection
# !       - **I to I** (bottom-right, row 7 in table): circular projection
# !         covering entire layer.
# !
# ! - **NB:** Color scales are different, so one **cannot** compare connection
# !   strengths between patches.

# ! Full detail, common color scale
# ! -------------------------------
s_cp.plot(globalColors=True)
pylab.show()

# ! This figure shows the same data as the one above, but now all patches use
# ! a common color scale, so full intensity color (either red or blue)
# ! indicates the strongest connectivity. From this we see that
# !
# ! - A to B/E is stronger than A to B/I
# ! - B/E to B/I is the strongest of all connections at the center
# ! - B/I to B/E is stronger than B/I to B/I

# ! Aggregate by groups
# ! -------------------
# ! For each pair of population groups, sum connections of the same type
# ! across populations.
s_cp.plot(aggrGroups=True)
pylab.show()

# ! In the figure above, all excitatory connections from B to B layer have been
# ! combined into one patch, as have all inhibitory connections from B to B.
# ! In the upper-right corner, all connections from layer A to layer B have
# ! been combined; the patch for inhibitory connections is missing, as there
# ! are none.

# ! Aggregate by groups and synapse models
# ! --------------------------------------
s_cp.plot(aggrGroups=True, aggrSyns=True)
pylab.show()
# ! When aggregating across synapse models, excitatory and inhibitory
# ! connections are combined. By default, excitatory connections are weights
# ! with +1, inhibitory connections with -1 in the sum. This may yield kernels
# ! with positive and negative values. They are shown on a red-white-blue scale
# ! as follows:
# !
# ! - White always represents 0.
# ! - Positive values are represented by increasingly saturated red.
# ! - Negative values are represented by increasingly saturated blue.
# ! - Colorscales are separate for red and blue:
# !
# !   * largest positive value: fully saturated red
# !   * largest negative value: fully saturated blue
# !
# ! - Each patch has its own colorscales.
# ! - When ``aggrSyns=True`` is combined with ``globalColors=True``,
# !   all patches use the same minimum and maximum in their red and blue
# !   color scales. The the minimum is the negative of the maximum, so that
# !   blue and red intesities can be compared.
s_cp.plot(aggrGroups=True, aggrSyns=True, globalColors=True)
pylab.show()

# ! - We can explicitly set the limits of the color scale; if values exceeding
# !   the limits are present, this is indicated by an arrowhead at the end of
# !   the colorbar. User-defined color limits need not be symmetric about 0.
s_cp.plot(aggrGroups=True, aggrSyns=True, globalColors=True,
          colorLimits=[-2, 3])
pylab.show()

# ! Save pattern to file
# ! --------------------
# s_cp.plot(file='simple_example.png')

# ! This saves the detailed diagram to the given file. If you want to save
# ! the pattern in several file formats, you can pass a tuple of file names,
# ! e.g., ``s_cp.plot(file=('a.eps', 'a.png'))``.
# !
# ! **NB:** Saving directly to PDF may lead to files with artifacts. We
# ! recommend to save to EPS and the convert to PDF.


# ! Build network in NEST
# ! ---------------------
import nest
import nest.topology as topo

# ! Create models
for model in s_model:
    nest.CopyModel(model[0], model[1], model[2])

# ! Create layers, store layer info in Python variable
for layer in s_layer:
    exec ('%s = topo.CreateLayer(layer[1])' % layer[0])

# ! Create connections, need to insert variable names
for conn in s_conn:
    eval('topo.ConnectLayers(%s,%s,conn[2])' % (conn[0], conn[1]))

nest.Simulate(10)
# ! **Ooops:*** Nothing happened? Well, it did, but pyreport cannot capture the
# ! output directly generated by NEST. The absence of an error message in this
# ! place shows that network construction and simulation went through.

# ! Inspecting the connections actually created
# ! :::::::::::::::::::::::::::::::::::::::::::
# ! The following block of messy and makeshift code plots the targets of the
# ! center neuron of the B/E population in the B/E and the B/I populations.
B_top = nest.GetStatus(RG, 'topology')[0]
ctr_id = topo.GetElement(RG,
                         [int(B_top['rows'] / 2), int(B_top['columns'] / 2)])

# find excitatory element in B
E_id = [gid for gid in ctr_id
        if nest.GetStatus([gid], 'model')[0] == 'E']

# get all targets, split into excitatory and inhibitory
alltgts = nest.GetStatus(
    nest.GetConnections(E_id, synapse_model='static_synapse'), 'target')
Etgts = [t for t in alltgts if nest.GetStatus([t], 'model')[0] == 'E']
Itgts = [t for t in alltgts if nest.GetStatus([t], 'model')[0] == 'I']

# obtain positions of targets
Etpos = tuple(zip(*topo.GetPosition(Etgts)))
Itpos = tuple(zip(*topo.GetPosition(Itgts)))

# plot excitatory
pylab.clf()
pylab.subplot(121)
pylab.scatter(Etpos[0], Etpos[1])
ctrpos = pylab.array(topo.GetPosition(E_id)[0])
ax = pylab.gca()
ax.add_patch(pylab.Circle(ctrpos, radius=0.02, zorder=99,
                          fc='r', alpha=0.4, ec='none'))
ax.add_patch(
    pylab.Rectangle(ctrpos + pylab.array((-0.4, -0.2)), 0.8, 0.4, zorder=1,
                    fc='none', ec='r', lw=3))
ax.add_patch(
    pylab.Rectangle(ctrpos + pylab.array((-0.2, -0.4)), 0.4, 0.8, zorder=1,
                    fc='none', ec='r', lw=3))
ax.add_patch(
    pylab.Rectangle(ctrpos + pylab.array((-0.5, -0.5)), 1.0, 1.0, zorder=1,
                    fc='none', ec='k', lw=3))
ax.set(aspect='equal', xlim=[-0.5, 0.5], ylim=[-0.5, 0.5],
       xticks=[], yticks=[])

# plot inhibitory
pylab.subplot(122)
pylab.scatter(Itpos[0], Itpos[1])
ctrpos = topo.GetPosition(E_id)[0]
ax = pylab.gca()
ax.add_patch(pylab.Circle(ctrpos, radius=0.02, zorder=99,
                          fc='r', alpha=0.4, ec='none'))
ax.add_patch(pylab.Circle(ctrpos, radius=0.1, zorder=2,
                          fc='none', ec='r', lw=2, ls='dashed'))
ax.add_patch(pylab.Circle(ctrpos, radius=0.2, zorder=2,
                          fc='none', ec='r', lw=2, ls='dashed'))
ax.add_patch(pylab.Circle(ctrpos, radius=0.3, zorder=2,
                          fc='none', ec='r', lw=2, ls='dashed'))
ax.add_patch(pylab.Circle(ctrpos, radius=0.5, zorder=2,
                          fc='none', ec='r', lw=3))
ax.add_patch(pylab.Rectangle((-0.5, -0.5), 1.0, 1.0, zorder=1,
                             fc='none', ec='k', lw=3))
ax.set(aspect='equal', xlim=[-0.5, 0.5], ylim=[-0.5, 0.5],
       xticks=[], yticks=[])
pylab.show()

# ! Thick red lines mark the mask, dashed red lines to the right one, two and
# ! three standard deviations. The sender location is marked by the red spot
# ! in the center. Layers are 40x40 in size.

# ! A more complex network
# ! ======================
# !
# ! This network has layers A and B, with E and I populations in B. The added
# ! complexity comes from the fact that we now have four synapse types: AMPA,
# ! NMDA, GABA_A and GABA_B. These synapse types are known to ConnPlotter.

# ! Setup and tabular display
c_layer, c_conn, c_model = ex.complex()
c_cp = cpl.ConnectionPattern(c_layer, c_conn)
showTextTable(c_cp, 'complex_tt')
# $ \centerline{\includegraphics{complex_tt.pdf}}

# ! Pattern in full detail
# ! ----------------------
c_cp.plot()
pylab.show()

# ! Note the following differences to the simple pattern case:
# !
# ! - For each pair of populations, e.g., B/E as sender and B/E as target,
# !   we now have two patches representing AMPA and NMDA synapse for the E
# !   population, GABA_A and _B for the I population.
# ! - Colors are as follows:
# !
# !   :AMPA: red
# !   :NMDA: orange
# !   :GABA_A: blue
# !   :GABA_B: purple
# ! - Note that the horizontal rectangular pattern (table line 3) describes
# !   AMPA synapses, while the vertical rectangular pattern (table line 4)
# !   describes NMDA synapses.

# ! Full detail, common color scale
# ! -------------------------------
c_cp.plot(globalColors=True)
pylab.show()

# ! As above, but now with a common color scale.
# ! **NB:** The patch for the B/I to B/I connection may look empty, but it
# ! actually shows a very light shade of red. Rules are as follows:
# !
# ! - If there is no connection between two populations, show the grey layer
# !   background.
# ! - All parts of the target layer that are outside the mask or strictly zero
# !   are off-white.
# ! - If it looks bright white, it is a very diluted shade of the color for the
# !   pertaining synpase type.

# ! Full detail, explicit color limits
# ! ----------------------------------
c_cp.plot(colorLimits=[0, 1])
pylab.show()

# ! As above, but the common color scale is now given explicitly.
# ! The arrow at the right end of the color scale indicates that the values
# ! in the kernels extend beyond +1.


# ! Aggregate by synapse models
# ! -----------------------------

# ! For each population pair, connections are summed across
# ! synapse models.
# !
# !  - Excitatory kernels are weighted with +1, inhibitory kernels with -1.
# !  - The resulting kernels are shown on a color scale ranging from red
# !    (inhibitory) via white (zero) to blue (excitatory).
# !  - Each patch has its own color scale
c_cp.plot(aggrSyns=True)
pylab.show()
# !
# ! - AMPA and NMDA connections from B/E to B/E are now combined to form a
# !   cross.
# ! - GABA_A and GABA_B connections from B/I to B/E are two concentric spots.

# ! Aggregate by population group
# ! ------------------------------
c_cp.plot(aggrGroups=True)
pylab.show()
# ! This is in many ways orthogonal to aggregation by synapse model:
# ! We keep synapse types separat, while we combine across populations. Thus,
# ! we have added the horizonal bar (B/E to B/E, row 3) with the spot
# ! (B/E to B/I, row 5).

# ! Aggregate by population group and synapse model
# ! -----------------------------------------------------------------
c_cp.plot(aggrGroups=True, aggrSyns=True)
pylab.show()
# ! All connection are combined for each pair of sender/target layer.


# ! CPTs using the total charge deposited (TCD) as intensity
# ! -----------------------------------------------------------
# ! TCD-based CPTs are currently only available for the ht_neuron, since
# ! ConnPlotter does not know how to obtain \int g(t) dt from NEST for other
# ! conductance-based model neurons.
# ! We need to create a separate ConnectionPattern instance for each membrane
# ! potential we want to use in the TCD computation
c_cp_75 = cpl.ConnectionPattern(c_layer, c_conn, intensity='tcd',
                                mList=c_model, Vmem=-75.0)
c_cp_45 = cpl.ConnectionPattern(c_layer, c_conn, intensity='tcd',
                                mList=c_model, Vmem=-45.0)

# ! In order to obtain a meaningful comparison between both membrane
# ! potentials, we use the same global color scale.

# ! V_m = -75 mV
# ! ::::::::::::::
c_cp_75.plot(colorLimits=[0, 150])
pylab.show()

# ! V_m = -45 mV
# ! ::::::::::::::
c_cp_45.plot(colorLimits=[0, 150])
pylab.show()
# ! Note that the NMDA projection virtually vanishes for V_m=-75mV, but is very
# ! strong for V_m=-45mV. GABA_A and GABA_B projections are also stronger,
# ! while AMPA is weaker for V_m=-45mV.

# ! Non-Dale network model
# ! ======================

# ! By default, ConnPlotter assumes that networks follow Dale's law, i.e.,
# ! either make excitatory or inhibitory connections. If this assumption
# ! is violated, we need to inform ConnPlotter how synapse types are grouped.
# ! We look at a simple example here.

# ! Load model
nd_layer, nd_conn, nd_model = ex.non_dale()

# ! We specify the synapse configuration using the synTypes argument:
# !
# ! - synTypes is a tuple.
# ! - Each element in the tuple represents a group of synapse models
# ! - Any sender can make connections with synapses from **one group only**.
# ! - Each synapse model is specified by a ``SynType``.
# ! - The SynType constructor takes three arguments:
# !
# !   * The synapse model name
# !   * The weight to apply then aggregating across synapse models
# !   * The color to use for the synapse type
# !
# ! - Synapse names must be unique, and must form a superset of all synapse
# !   models in the network.
nd_cp = cpl.ConnectionPattern(nd_layer, nd_conn, synTypes=(
    (cpl.SynType('exc', 1.0, 'b'), cpl.SynType('inh', -1.0, 'r')),))
showTextTable(nd_cp, 'non_dale_tt')
# $ \centerline{\includegraphics{non_dale_tt.pdf}}

nd_cp.plot()
pylab.show()

# ! Note that we now have red and blue patches side by side, as the same
# ! population can make excitatory and inhibitory connections.

# ! Configuring the ConnectionPattern display
# ! =========================================

# ! I will now show you a few ways in which you can configure how ConnPlotter
# ! shows connection patterns.

# ! User defined synapse types
# ! --------------------------
# !
# ! By default, ConnPlotter knows two following sets of synapse types.
# !
# ! exc/inh
# !   - Used automatically when all connections have the same synapse_model.
# !   - Connections with positive weight are assigned model exc, those with
# !     negative weight model inh.
# !   - When computing totals, exc has weight +1, inh weight -1
# !   - Exc is colored blue, inh red.
# !
# ! AMPA/NMDA/GABA_A/GABA_B
# !   - Used if the set of ``synapse_model`` s in the network is a subset of
# !     those four types.
# !   - AMPA/NMDA carry weight +1, GABA_A/GABA_B weight -1.
# !   - Colors are as follows:
# !
# !      :AMPA: blue
# !      :NMDA: green
# !      :GABA_A: red
# !      :GABA_B: magenta
# !
# !
# ! We saw a first example of user-defined synapse types in the non-Dale
# ! example above. In that case, we only changed the grouping. Here, I will
# ! demonstrate the effect of different ordering, weighting, and color
# ! specifications. We use the complex model from above as example.
# !
# ! *NOTE*: It is most likey a *bad idea* to change the colors or placement of
# ! synapse types. If everyone uses the same design rules, we will all be able
# ! to read each others figures much more easily.

# ! Placement of synapse types
# ! ::::::::::::::::::::::::::
# !
# ! The ``synTypes`` nested tuple defines the placement of patches for
# ! different synapse models. Default layout is
# !
# ! ====== ======
# ! AMPA   NMDA
# ! GABA_A GABA_B
# ! ====== ======
# !
# ! All four matrix elements are shown in this layout only when using
# ! ``mode='layer'`` display. Otherwise, one or the other row is shown.
# ! Note that synapses that can arise from a layer simultaneously, must
# ! always be placed on one matrix row, i.e., in one group. As an example,
# ! we now invert placement, without any other changes:

cinv_syns = ((cpl.SynType('GABA_B', -1, 'm'), cpl.SynType('GABA_A', -1, 'r')),
             (cpl.SynType('NMDA', 1, 'g'), cpl.SynType('AMPA', 1, 'b')))
cinv_cp = cpl.ConnectionPattern(c_layer, c_conn, synTypes=cinv_syns)
cinv_cp.plot()
pylab.show()

# ! Notice that on each row the synapses are exchanged compared to the original
# ! figure above. When displaying by layer, also the rows have traded place:
cinv_cp.plot(aggrGroups=True)
pylab.show()

# ! Totals are not affected:
cinv_cp.plot(aggrGroups=True, aggrSyns=True)
pylab.show()

# ! Weighting of synapse types in ``totals`` mode
# ! :::::::::::::::::::::::::::::::::::::::::::::
# !
# ! Different synapses may have quite different efficacies, so weighting them
# ! all with +-1 when computing totals may give a wrong impression. Different
# ! weights can be supplied as second argument to SynTypes(). We return to the
# ! normal placement of synapses and
# ! create two examples with very different weights:
cw1_syns = ((cpl.SynType('AMPA', 10, 'b'), cpl.SynType('NMDA', 1, 'g')),
            (cpl.SynType('GABA_A', -2, 'g'), cpl.SynType('GABA_B', -10, 'b')))
cw1_cp = cpl.ConnectionPattern(c_layer, c_conn, synTypes=cw1_syns)
cw2_syns = ((cpl.SynType('AMPA', 1, 'b'), cpl.SynType('NMDA', 10, 'g')),
            (cpl.SynType('GABA_A', -20, 'g'), cpl.SynType('GABA_B', -1, 'b')))
cw2_cp = cpl.ConnectionPattern(c_layer, c_conn, synTypes=cw2_syns)

# ! We first plot them both in population mode
cw1_cp.plot(aggrSyns=True)
pylab.show()

cw2_cp.plot(aggrSyns=True)
pylab.show()

# ! Finally, we plot them aggregating across groups and synapse models
cw1_cp.plot(aggrGroups=True, aggrSyns=True)
pylab.show()

cw2_cp.plot(aggrGroups=True, aggrSyns=True)
pylab.show()

# ! Alternative colors for synapse patches
# ! ::::::::::::::::::::::::::::::::::::::
# ! Different colors can be specified using any legal color specification.
# ! Colors should be saturated, as they will be mixed with white. You may
# ! also provide a colormap explicitly. For this example, we use once more
# ! normal placement and weights. As all synapse types are shown in layer
# ! mode, we use that mode for display here.
cc_syns = (
    (cpl.SynType('AMPA', 1, 'maroon'), cpl.SynType('NMDA', 1, (0.9, 0.5, 0))),
    (cpl.SynType('GABA_A', -1, '0.7'), cpl.SynType('GABA_B', 1, pylab.cm.hsv)))
cc_cp = cpl.ConnectionPattern(c_layer, c_conn, synTypes=cc_syns)
cc_cp.plot(aggrGroups=True)
pylab.show()
# ! We get the following colors:
# !
# ! AMPA     brownish
# ! NMDA     golden orange
# ! GABA_A   jet colormap from red (max) to blue (0)
# ! GABA_B   grey
# !
# ! **NB:** When passing an explicit colormap, parts outside the mask will be
# ! shown to the "bad" color of the colormap, usually the "bottom" color in the
# ! map. To let points outside the mask appear in white, set the bad color of
# ! the colormap; unfortunately, this modifies the colormap.
pylab.cm.hsv.set_bad(cpl.colormaps.bad_color)
ccb_syns = (
    (cpl.SynType('AMPA', 1, 'maroon'),
     cpl.SynType('NMDA', 1, (0.9, 0.5, 0.1))),
    (cpl.SynType('GABA_A', -1, '0.7'),
     cpl.SynType('GABA_B', 1, pylab.cm.hsv)))
ccb_cp = cpl.ConnectionPattern(c_layer, c_conn, synTypes=ccb_syns)
ccb_cp.plot(aggrGroups=True)
pylab.show()

# ! Other configuration options
# ! ---------------------------
# !
# ! Some more adjustments are possible by setting certain module properties.
# ! Some of these need to be set before ConnectionPattern() is constructed.
# !

# ! Background color for masked parts of each patch
cpl.colormaps.bad_color = 'cyan'

# ! Background for layers
cpl.plotParams.layer_bg = (0.8, 0.8, 0.0)

# ! Resolution for patch computation
cpl.plotParams.n_kern = 5

# ! Physical size of patches: longest egde of largest patch, in mm
cpl.plotParams.patch_size = 40

# ! Margins around the figure (excluding labels)
cpl.plotParams.margins.left = 40
cpl.plotParams.margins.top = 30
cpl.plotParams.margins.bottom = 15
cpl.plotParams.margins.right = 30

# ! Fonts for layer and population labels
import matplotlib.font_manager as fmgr

cpl.plotParams.layer_font = fmgr.FontProperties(family='serif', weight='bold',
                                                size='xx-large')
cpl.plotParams.pop_font = fmgr.FontProperties('small')

# ! Orientation for layer and population label
cpl.plotParams.layer_orientation = {'sender': 'vertical', 'target': 60}
cpl.plotParams.pop_orientation = {'sender': 'horizontal', 'target': -45}

# ! Font for legend titles and ticks, tick placement, and tick format
cpl.plotParams.legend_title_font = fmgr.FontProperties(family='serif',
                                                       weight='bold',
                                                       size='large')
cpl.plotParams.legend_tick_font = fmgr.FontProperties(family='sans-serif',
                                                      weight='light',
                                                      size='xx-small')
cpl.plotParams.legend_ticks = [0, 1, 2]
cpl.plotParams.legend_tick_format = '%.1f pA'

cx_cp = cpl.ConnectionPattern(c_layer, c_conn)
cx_cp.plot(colorLimits=[0, 2])
pylab.show()

# ! Several more options are available to control the format of the color bars
# ! (they all are members of plotParams):
# !  * legend_location : if 'top', place synapse name atop color bar
# !  * cbwidth : width of single color bar relative to figure
# !  * margins.colbar : height of lower margin set aside for color bar, in mm
# !  * cbheight : height of single color bar relative to margins.colbar
# !  * cbwidth : width of single color bar relative to figure width
# !  * cbspace : spacing between color bars, relative to figure width
# !  * cboffset : offset of first color bar from left margin, relative to
# !    figure width

# ! You can also specify the width of the final figure, but this may not work
# ! well with on-screen display or here in pyreport. Width is in mm.
# ! Note that left and right margin combined are 70mm wide, so only 50mm are
# ! left for the actual CPT.
cx_cp.plot(fixedWidth=120)
pylab.show()

# ! If not using pyreport, we finally show and block
if not using_pyreport:
    print("")
    print("The connplotter_tutorial script is done. " +
          "Call pylab.show() and enjoy the figures!")
    print(
        "You may need to close all figures manually " +
        "to get the Python prompt back.")
    print("")
    pylab.show = pylab_show
