1# -*- coding: utf-8 -*- 2# 3# plot_weight_matrices.py 4# 5# This file is part of NEST. 6# 7# Copyright (C) 2004 The NEST Initiative 8# 9# NEST is free software: you can redistribute it and/or modify 10# it under the terms of the GNU General Public License as published by 11# the Free Software Foundation, either version 2 of the License, or 12# (at your option) any later version. 13# 14# NEST is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# along with NEST. If not, see <http://www.gnu.org/licenses/>. 21 22""" 23Plot weight matrices example 24---------------------------- 25 26This example demonstrates how to extract the connection strength 27for all the synapses among two populations of neurons and gather 28these values in weight matrices for further analysis and visualization. 29 30All connection types between these populations are considered, i.e., 31four weight matrices are created and plotted. 32 33""" 34 35############################################################################### 36# First, we import all necessary modules to extract, handle and plot 37# the connectivity matrices 38 39import numpy as np 40import matplotlib.pyplot as plt 41import nest 42import matplotlib.gridspec as gridspec 43from mpl_toolkits.axes_grid1 import make_axes_locatable 44 45############################################################################### 46# We now specify a function to extract and plot weight matrices for all 47# connections among `E_neurons` and `I_neurons`. 48# 49# We initialize all the matrices, whose dimensionality is determined by the 50# number of elements in each population. 51# Since in this example, we have 2 populations (E/I), :math:`2^2` possible 52# synaptic connections exist (EE, EI, IE, II). 53# 54# Note the use of "post-pre" notation when referring to synaptic connections. 55# As a matter of convention in computational neuroscience, we refer to the 56# connection from inhibitory to excitatory neurons (I->E) as EI (post-pre) and 57# connections from excitatory to inhibitory neurons (E->I) as IE (post-pre). 58 59 60def plot_weight_matrices(E_neurons, I_neurons): 61 62 W_EE = np.zeros([len(E_neurons), len(E_neurons)]) 63 W_EI = np.zeros([len(I_neurons), len(E_neurons)]) 64 W_IE = np.zeros([len(E_neurons), len(I_neurons)]) 65 W_II = np.zeros([len(I_neurons), len(I_neurons)]) 66 67 a_EE = nest.GetConnections(E_neurons, E_neurons) 68 69 # Using `get`, we can extract the value of the connection weight, 70 # for all the connections between these populations 71 c_EE = a_EE.weight 72 73 # Repeat the two previous steps for all other connection types 74 a_EI = nest.GetConnections(I_neurons, E_neurons) 75 c_EI = a_EI.weight 76 a_IE = nest.GetConnections(E_neurons, I_neurons) 77 c_IE = a_IE.weight 78 a_II = nest.GetConnections(I_neurons, I_neurons) 79 c_II = a_II.weight 80 81 # We now iterate through the range of all connections of each type. 82 # To populate the corresponding weight matrix, we begin by identifying 83 # the source-node_id (by using .source) and the target-node_id. 84 # For each node_id, we subtract the minimum node_id within the corresponding 85 # population, to assure the matrix indices range from 0 to the size of 86 # the population. 87 88 # After determining the matrix indices [i, j], for each connection 89 # object, the corresponding weight is added to the entry W[i,j]. 90 # The procedure is then repeated for all the different connection types. 91 a_EE_src = a_EE.source 92 a_EE_trg = a_EE.target 93 a_EI_src = a_EI.source 94 a_EI_trg = a_EI.target 95 a_IE_src = a_IE.source 96 a_IE_trg = a_IE.target 97 a_II_src = a_II.source 98 a_II_trg = a_II.target 99 100 for idx in range(len(a_EE)): 101 W_EE[a_EE_src[idx] - min(E_neurons), 102 a_EE_trg[idx] - min(E_neurons)] += c_EE[idx] 103 for idx in range(len(a_EI)): 104 W_EI[a_EI_src[idx] - min(I_neurons), 105 a_EI_trg[idx] - min(E_neurons)] += c_EI[idx] 106 for idx in range(len(a_IE)): 107 W_IE[a_IE_src[idx] - min(E_neurons), 108 a_IE_trg[idx] - min(I_neurons)] += c_IE[idx] 109 for idx in range(len(a_II)): 110 W_II[a_II_src[idx] - min(I_neurons), 111 a_II_trg[idx] - min(I_neurons)] += c_II[idx] 112 113 fig = plt.figure() 114 fig.subtitle('Weight matrices', fontsize=14) 115 gs = gridspec.GridSpec(4, 4) 116 ax1 = plt.subplot(gs[:-1, :-1]) 117 ax2 = plt.subplot(gs[:-1, -1]) 118 ax3 = plt.subplot(gs[-1, :-1]) 119 ax4 = plt.subplot(gs[-1, -1]) 120 121 plt1 = ax1.imshow(W_EE, cmap='jet') 122 123 divider = make_axes_locatable(ax1) 124 cax = divider.append_axes("right", "5%", pad="3%") 125 plt.colorbar(plt1, cax=cax) 126 127 ax1.set_title('W_{EE}') 128 plt.tight_layout() 129 130 plt2 = ax2.imshow(W_IE) 131 plt2.set_cmap('jet') 132 divider = make_axes_locatable(ax2) 133 cax = divider.append_axes("right", "5%", pad="3%") 134 plt.colorbar(plt2, cax=cax) 135 ax2.set_title('W_{EI}') 136 plt.tight_layout() 137 138 plt3 = ax3.imshow(W_EI) 139 plt3.set_cmap('jet') 140 divider = make_axes_locatable(ax3) 141 cax = divider.append_axes("right", "5%", pad="3%") 142 plt.colorbar(plt3, cax=cax) 143 ax3.set_title('W_{IE}') 144 plt.tight_layout() 145 146 plt4 = ax4.imshow(W_II) 147 plt4.set_cmap('jet') 148 divider = make_axes_locatable(ax4) 149 cax = divider.append_axes("right", "5%", pad="3%") 150 plt.colorbar(plt4, cax=cax) 151 ax4.set_title('W_{II}') 152 plt.tight_layout() 153 154################################################################################# 155# The script iterates through the list of all connections of each type. 156# To populate the corresponding weight matrix, we identify the source-node_id 157# (first element of each connection object, `n[0]`) and the target-node_id (second 158# element of each connection object, `n[1]`). 159# For each `node_id`, we subtract the minimum `node_id` within the corresponding 160# population, to assure the matrix indices range from 0 to the size of the 161# population. 162# 163# After determining the matrix indices `[i, j]`, for each connection object, the 164# corresponding weight is added to the entry `W[i,j]`. The procedure is then 165# repeated for all the different connection types. 166# 167# We then plot the figure, specifying the properties we want. For example, we 168# can display all the weight matrices in a single figure, which requires us to 169# use ``GridSpec`` to specify the spatial arrangement of the axes. 170# A subplot is subsequently created for each connection type. Using ``imshow``, 171# we can visualize the weight matrix in the corresponding axis. We can also 172# specify the colormap for this image. 173# Using the ``axis_divider`` module from ``mpl_toolkits``, we can allocate a small 174# extra space on the right of the current axis, which we reserve for a 175# colorbar. 176# We can set the title of each axis and adjust the axis subplot parameters. 177# Finally, the last three steps are repeated for each synapse type. 178