#!========================
#! 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, [B_top['rows']/2, 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.FindConnections(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 = zip(*topo.GetPosition(Etgts))
Itpos = 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