<jupyter_start><jupyter_text>Run a single cellIn this notebook we will run a single neuron with simple dendritic structures and some patterned inputs (inhibitory and excitatory) with different tunings.<jupyter_code>%load_ext autoreload
%autoreload 2
from brian2 import *
import numpy as np
import holoviews as hv
import dendrites_fun as denfun
%matplotlib inline
hv.extension('matplotlib', 'bokeh')<jupyter_output><empty_output><jupyter_text>Define soma and compartment equations<jupyter_code>start_scope() # brian will start keeping track of things from here.
# !!! Always run the whole notebook from the top for new simulations

# parameter settings
gm = 1e-4*siemens/cm**2   # membrane conductance
Em = -70*mV               # membrane reversal potential
Vt = -50*mV               # somatic spiking threshold
Vr = -70*mV               # somatic reset potential
Ee = 0*mV                 # excitatory reversal potential
Ei = -70*mV               # inhibitory reversal potential
taue = 2*ms               # excitatory timescale
taui = 8*ms               # inhibitory timescale

# Model equations
# These define the input currents, and conductances
# The voltage will then be given by dV/dt = Im + Ie + Ie
eqs='''
Im = gm*(Em-v) : amp/meter**2
Ie = ge*(Ee-v) : amp (point current)
Ii = gi*(Ei-v) : amp (point current)
dge/dt = -ge/taue : siemens
dgi/dt = -gi/taui : siemens
'''<jupyter_output><empty_output><jupyter_text>Define the morphology and spatial neuron group<jupyter_code>soma_d = 30  # soma diameter
den_d= 10        # dendrite diameter
den_l= 100       # dendrite length
den_n= 10        # dendrite compartment number
den_N= 2      # number of dendrites

# define the soma
morpho = Soma(soma_d * um)

# add the dendrites
for i in range(den_N):
    morpho['den' + str(i + 1)] = Cylinder(diameter=den_d * um, length=den_l * um, n=den_n)
    
# setup spatial neuron group
# note the parameter 'threshold_location=0'. This makes it so spikes are only detected 
# in the 0'th compartment (the soma), and the dendrites are passive.
neuron = SpatialNeuron(morphology=morpho, model=eqs, Cm=1*uF/cm**2, Ri=100*ohm*cm,
                       threshold='v>Vt', threshold_location=0,
                       method='euler')
neuron.v = Em # starting voltage set the membrane reversal potential

# Reset the entire neuron when there is a spike
reset = Synapses(neuron, neuron, on_pre='v =Vr')
reset.connect('i == 0')  # Connects the spike initiation compartment to all compartments<jupyter_output><empty_output><jupyter_text>Define the input groups<jupyter_code># Set input orientations 
c = 0 # centre (excitatory) orientation
s = 0 # surround (inhibitory) orientation

# setup stimulation
N_inputs_e, N_inputs_i = 90, 90 # total number of excitatory and inhibitory inputs. 
nA       = 10 # number of different preferred orientations

# Below we set up the excitatory and inhibitory input groups.
# stimulation_e and stimulation_i are neuron groups that emit poisson spikes with rates determined by the preferred orientations
# r_e and r_i give the average rates of each neuron in the respective stimulation group
# ang_e and ang_i give their preferred orientations
# check the setupstimulation function help to understand all the different input parameters
# excitatory (center tuned)
stimulation_e,r_e,ang_e = denfun.setupstimulation(N=N_inputs_e,nA=nA, stim=c,p=0,kn=0,k=5,A=2000)

# inhibitory (surround tuned)
stimulation_i,r_i,ang_i = denfun.setupstimulation(N=N_inputs_i,nA=nA, stim=s,p=0,kn=0,k=5,A=2000)

# redefine N_inputs in case it was different after definition (this is possible when we don't have an
# even distribution of input orientations)
N_inputs_e = len(ang_e)
N_inputs_i = len(ang_i)

# let's plot the distribution of preferred orientations of the excitatory inputs (B), 
# and input firing rates across preferred orientations for the above stimulus (A)
fig = hv.Curve(zip(ang_e, r_e), kdims='Preferred orientation (radians)', vdims='Firing rate (Hz)')
fig += hv.Histogram(np.histogram(ang_e, bins=nA), kdims='Preferred orientation (radians)')
fig<jupyter_output><empty_output><jupyter_text>Connect the inputs to the neural dendrites<jupyter_code># connect the excitatory stimulation
Se = Synapses(stimulation_e,neuron,'w : siemens', on_pre='ge += w') # connect the stimulation neurons to the neuron, 
                                                     # the post-synaptic ge will jump up by 'w' when the pre neuron spikes
                                                     # This is where we would want to plug in the learning rule

# connect the inputs randomly or nonrandomly with the 'pos' option ('random' or 'nonrandom'):
pos_e = denfun.ConnectStim(neuron,stimulation_e,Se,pos='random') 
Se.w = (5 + rand(N_inputs_e)*25)*nS# random starting connection weights

# connect the inhibitory stimulation
Si = Synapses(stimulation_i,neuron,'w : siemens', on_pre='gi += w') # connect the stimulation neurons to the neuron
pos_i = denfun.ConnectStim(neuron,stimulation_i,Si,pos='random')
Si.w = (5 + rand(N_inputs_i)*25)*nS # random starting connection weights<jupyter_output><empty_output><jupyter_text>Plot resulting inputs<jupyter_code>%%output size=200
%%opts Curve plot[fontsize=15] Scatter (color='k', marker='o', s=800) [fontsize=15] 
%%opts Histogram [xticks=16] 
%%opts Points (cmap='viridis') [color_index=2] Points.I (marker='s')
fig_e = denfun.plotmorph(ang_e,den_N,pos=pos_e, w=np.array(Se.w), group='E')
fig_i = denfun.plotmorph(ang_i,den_N,pos=pos_i, w=np.array(Si.w), group='I')
fig_e+fig_i<jupyter_output><empty_output><jupyter_text>Color indicates preferred orientation, and size the input weight. Circles are excitatory inputs, squares inhibitory.  Define a neuron<jupyter_code># setup monitors
V = StateMonitor(neuron, 'v', record=[0])
Sstim_e = SpikeMonitor(stimulation_e)
Sstim_i = SpikeMonitor(stimulation_i)
Ssoma = SpikeMonitor(neuron,record=[0])

# run
Tend=10
run(Tend*ms)<jupyter_output><empty_output><jupyter_text>Plot with HoloViews instead<jupyter_code>%%opts Curve [aspect=5] Overlay [aspect=5] Scatter [aspect=5]
%%opts Layout [sublabel_format=None]
%%output dpi=100
# Plot the results
fig = hv.Layout()
xdim = hv.Dimension('Time (s)', range=(0, Tend))

fig += hv.Scatter(zip(Ssoma.t/ms, Ssoma.i-0.04), kdims=xdim, vdims='Output spikes').opts(color='k')

fig += hv.Curve(zip(V.t/ms, V.v[0, :]/mV), kdims=xdim, vdims='Voltage (V)/spikes').opts(color='k')

fig += hv.Scatter(zip(Sstim_e.t/ms, Sstim_e.i), kdims=xdim, vdims='Excitatory spikes').opts(color='r')

fig += hv.Scatter(zip(Sstim_i.t/ms, Sstim_i.i), kdims=xdim, vdims='Inhibotory spikes').opts(color='b')

fig.cols(1)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10980922337389214, 'fraction_numerical': 0.014120474688298032, 'mean_word_length': 4.715021459227468, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '8', 'dir': 'jupyter-structured-clean-dedup', 'id': '288492', 'license': 'MIT', 'n_tokens_mistral': 2388, 'n_tokens_neox': 2193, 'n_words': 648, 'path': 'Run_single_cell.ipynb', 'repo_name': 'swkeemink/dendrites-with-tuned-inputs', 'size': '6657'}