```python
from resources.workspace import *
```

$
%MACRO DEFINITION
\newcommand{\Reals}{\mathbb{R}}
\newcommand{\Imags}{i\Reals}
\newcommand{\Integers}{\mathbb{Z}}
\newcommand{\Naturals}{\mathbb{N}}
%
\newcommand{\Expect}[0]{\mathop{}\! \mathbb{E}}
\newcommand{\NormDist}{\mathop{}\! \mathcal{N}}
%
\newcommand{\mat}[1]{{\mathbf{{#1}}}}
%\newcommand{\mat}[1]{{\pmb{\mathsf{#1}}}}
\newcommand{\bvec}[1]{{\mathbf{#1}}}
%
\newcommand{\trsign}{{\mathsf{T}}}
\newcommand{\tr}{^{\trsign}}
%
\newcommand{\I}[0]{\mat{I}}
\newcommand{\K}[0]{\mat{K}}
\newcommand{\bP}[0]{\mat{P}}
\newcommand{\F}[0]{\mat{F}}
\newcommand{\bH}[0]{\mat{H}}
\newcommand{\bF}[0]{\mat{F}}
\newcommand{\R}[0]{\mat{R}}
\newcommand{\Q}[0]{\mat{Q}}
\newcommand{\B}[0]{\mat{B}}
\newcommand{\Ri}[0]{\R^{-1}}
\newcommand{\Bi}[0]{\B^{-1}}
\newcommand{\X}[0]{\mat{X}}
\newcommand{\A}[0]{\mat{A}}
\newcommand{\Y}[0]{\mat{Y}}
\newcommand{\E}[0]{\mat{E}}
\newcommand{\U}[0]{\mat{U}}
\newcommand{\V}[0]{\mat{V}}
%
\newcommand{\x}[0]{\bvec{x}}
\newcommand{\y}[0]{\bvec{y}}
\newcommand{\q}[0]{\bvec{q}}
\newcommand{\br}[0]{\bvec{r}}
\newcommand{\bb}[0]{\bvec{b}}
%
\newcommand{\cx}[0]{\text{const}}
\newcommand{\norm}[1]{\|{#1}\|}
\newcommand{\tn}[1]{#1}
%
\newcommand{\bx}[0]{\bvec{\bar{x}}}
\newcommand{\barP}[0]{\mat{\bar{P}}}
\newcommand{\barK}[0]{\mat{\bar{K}}}
\newcommand{\D}[0]{\mat{D}}
\newcommand{\Dobs}[0]{\mat{D}_{\text{obs}}}
\newcommand{\Dmod}[0]{\mat{D}_{\text{mod}}}
\newcommand{\ones}[0]{\bvec{1}}
%
$In this section we're going to code an EnKF implementation using numpy.
# The EnKF algorithm
is given in the following.

As with the KF, the EnKF consists of the recursive application of
a forecast step and an analysis step.
This presentation follows the traditional template, presenting the EnKF as the "the Monte Carlo version of the KF
where the state covariance is estimated by the ensemble covariance".
It is not obvious that this postulated method should work;
indeed, it is only justified upon inspection of its properties,
deferred to later.

The time indices of the state and conditioning are implied
by the superscript $f$ or $a$ for the ensemble.
This indicates that $\{\x_n^f\}_{n=1}^N$ (resp. $\{\x_n^a\}_{n=1}^N$) is a forecast (resp. analysis) ensemble,
and is also used for the derivative objects, $\E, \X, \bx, \barP$.

### The forecast step
For a given, implicit, time index, $k$,
assume $\{\x_n^a\}_{n=1}^N$ is an iid. sample from $p(\x_{k-1} \mid \y_1,\ldots, \y_{k-1})$.
The forecast step of the EnKF consists of a Monte Carlo simulation
of the forecast dynamics for each $\x_n^a$:
$$
	\forall n, \quad \x^f_n = f(\x_n^a) + \q_n  \, , \\
$$
where the columns of $\q_n$ are sampled iid. from $\NormDist(0,\Q)$.
The ensemble, $\{\x_n^f\}_{n=1}^N$, is then an iid. sample from the forecast pdf,
$p(\x_k \mid \y_1,\ldots,\y_{k-1})$.

### The analysis update step
of the ensemble is given by:
$$\begin{align}
	\forall n, \quad \x^\tn{a}_n &= \x_n^\tn{f} + \barK \left\{\y - \br_n - h(\x_n^\tn{f}) \right\}
	\, , \\
	\text{or,}\quad
	\E^\tn{a} &=  \E^\tn{f}  + \barK \left\{\y\ones\tr - \Dobs - h(\E^\tn{f}) \right\} \, ,
\end{align}
$$
where the "observation perturbations", $\br_n$, are sampled iid. from $\NormDist(0,\R)$
and form the columns of $\Dobs$, and $h$ is applied column-wise to $\E^\tn{f}$.
The gain $\barK$ is defined by inserting the estimates for
 * (i) $\bP^\tn{f} \bH\tr$: the cross-covariance between $\x^\tn{f}$ and $h(\x^\tn{f})$, and
 * (ii) $\bH \bP^\tn{f} \bH\tr$: the covariance matrix of $h(\x^\tn{f})$,

in the formula for $\K$ ( eqn K1 of [T5](T5%20-%20Multivariate%20Kalman.ipynb) with $\bP^f = \B$)
Using the estimators from [T7](T7%20-%20Ensemble%20%5BMonte-Carlo%5D%20approach.ipynb) yields
$$\begin{align}
	\barK &= \X \Y\tr ( \Y \Y\tr + (N-1) \R )^{-1} \, ,
\end{align}
$$
where $\Y \in \Reals^{P \times N}$
is the centered, *observed* ensemble.

The EnKF is summarized in the animation below.

```python
#EnKF_animation
```

#### Exc 1:
Use the Woodbury identities to show that K = ...

#### Exc 2:
Show that the EnKF mean update conforms to the KF formulae.

We will make use of `estimate_mean_and_cov` and `estimate_cross_cov` from the previous section. Paste them in below.

```python
# def estimate_mean_and_cov ...
```

## Experimental setup

Before making the EnKF, we'll also set up an experiment to test it with. To that end, we'll use the Lorenz-63 model, from [T4](T4 - Dynamical systems, chaos, Lorenz.ipynb). The coupled ODEs are recalled here, but with some of the paremeters fixed.

```python
M = 3 # ndim

def dxdt(x):
    sig  = 10.0
    rho  = 28.0
    beta = 8.0/3
    x,y,z = x
    d     = np.zeros(3)
    d[0]  = sig*(y - x)
    d[1]  = rho*x - y - x*z
    d[2]  = x*y - beta*z
    return d
```

Next, we make a "black box" forecast model $f$ out of $\frac{d \mathbf{x}}{dt}$ such that $\mathbf{x}(t+dt) = f(\mathbf{x}(t),t,dt)$. We'll make use of the "4th order Runge-Kutta" integrator `rk4`.

```python
def f(E, t0, dt):

    def step(x0):
        return rk4(lambda t,x: dxdt(x), x0, t0, dt)

    if E.ndim == 1:
        # Truth (single state vector) case
        E = step(E)
    else:
        # Ensemble case
        for n in range(E.shape[1]):
            E[:,n] = step(E[:,n])

    return E

Q_chol = zeros((M,M))
Q      = Q_chol @ Q_chol.T
```

Notice the loop over each ensemble member. For better performance, this should be vectorized, if possible. Or, if the forecast model is computationally demanding (as is typically the case in real applications), the loop should be parallellized: i.e. the forecast simulations should be distributed to seperate computers.

The following are the time settings that we will use

```python
dt    = 0.01           # integrational time step
dkObs = 25             # number of steps between observations
dtObs = dkObs*dt       # time between observations
KObs  = 60             # total number of observations
K     = dkObs*(KObs+1) # total number of time steps
```

Initial conditions

```python
mu0     = array([1.509, -1.531, 25.46])
P0_chol = eye(3)
P0      = P0_chol @ P0_chol.T
```

Observation model settings

```python
p = 3 # ndim obs
def h(E, t):
    if E.ndim == 1: return E[:p]
    else:           return E[:p,:]

R_chol = sqrt(2)*eye(p)
R      = R_chol @ R_chol.T
```

Generate synthetic truth (`xx`) and observations (`yy`)

```python
# Init
xx    = zeros((K+1   ,M))
yy    = zeros((KObs+1,p))
xx[0] = mu0 + P0_chol @ randn(M)

# Loop
for k in range(1,K+1):
    xx[k]  = f(xx[k-1],(k-1)*dt,dt)
    xx[k] += Q_chol @ randn(M)
    if not k%dkObs:
        kObs = k//dkObs-1
        yy[kObs] = h(xx[k],nan) + R_chol @ randn(p)
```

## EnKF implementation

**Exc 4:** Complete the code below

```python
mu = zeros((K+1,M))

# Useful linear algebra: compute B/A
def divide_1st_by_2nd(B,A):
    return nla.solve(A.T,B.T).T

def my_EnKF(N):
    # Init ensemble
    ...
    for k in range(1,K+1):
        # Forecast
        t   = k*dt
        # use model
        E   = ...
        # add noise
        E  += ...
        if not k%dkObs:
            # Analysis
            y        = yy[k//dkObs-1] # current observation
            hE       = h(E,t)         # obsrved ensemble
            # Compute ensemble moments
            BH       = ...
            HBH      = ...
            # Compute Kalman Gain
            KG       = ...
            # Generate perturbations
            Perturb  = ...
            # Update ensemble with KG
            E       +=
        # Save statistics
        mu[k] = mean(E,axis=1)
```

Notice that we only store some stats (`mu`). This is because in large systems, keeping the entire ensemble in memory is probably too much.

```python
#show_answer('EnKF v1')
```

Now let's try out its capabilities

```python
# Run assimilation
my_EnKF(10)

# Plot results
plt.subplot(311)
plt.plot(dt   *arange(K+1)     ,mu[:,0],'k')
plt.plot(dt   *arange(K+1)     ,xx[:,0],'b')
plt.plot(dtObs*arange(1,KObs+2),yy[:,0],'k*')
plt.subplot(312)
plt.plot(dt   *arange(K+1)     ,mu[:,1],'k')
plt.plot(dt   *arange(K+1)     ,xx[:,1],'b')
plt.plot(dtObs*arange(1,KObs+2),yy[:,1],'k*')
plt.subplot(313)
plt.plot(dt   *arange(K+1)     ,mu[:,2],'k')
plt.plot(dt   *arange(K+1)     ,xx[:,2],'b')
plt.plot(dtObs*arange(1,KObs+2),yy[:,2],'k*')
```

**Exc 6:** The visuals of the plots are nice. But it would be good to have a summary statistic of the accuracy performance of the filter. Make a function `average_rmse(xx,mu)` that computes $ \frac{1}{K+1} \sum_{k=0}^K \sqrt{\frac{1}{M} \| \overline{\mathbf{x}}_k - \mathbf{x}_k \|_2^2} \, .$

```python
def average_rmse(xx,mu):
    ### INSERT ANSWER ###
    return average

# Test
average_rmse(xx,mu)
```

```python
#show_answer('rmse')
```

**Exc 8:**
 * (a). Repeat the above expriment, but now observing only the first (0th) component of the state.

```python
#show_answer('Repeat experiment a')
```

 * (b). Put a `seed()` command in the right place so as to be able to recreate exactly the same results from an experiment.

```python
#show_answer('Repeat experiment b')
```

 * (c). Use $N=5$, and repeat the experiments. This is quite a small ensemble size, and quite often it will yield divergence: the EnKF "definitely loses track" of the truth, typically because of strong nonlinearity in the forecast models, and underestimation (by $\overline{\mathbf{P}})$ of the actual errors. Repeat the experiment with different seeds until you observe in the plots that divergence has happened.
 * (d). Implement "multiplicative inflation" to remedy the situation; this is a factor that should spread the ensemble further apart; a simple version is to inflate the perturbations. Implement it, and tune its value to try to avoid divergence.

```python
#show_answer('Repeat experiment cd')
```

### Next: [Benchmarking with DAPPER](T9 - Benchmarking with DAPPER.ipynb)

tutorials/T8 - Writing your own EnKF.ipynb


# Figure 6

```python
from sympy import symbols, exp, solve, logcombine, simplify, Piecewise, lambdify, N, init_printing, Eq
import numpy
import scipy.stats as ss
from sympy.physics.units import seconds, siemens, volts, farads, amperes, milli, micro, nano, pico, ms, s, kg, meters
from matplotlib import pyplot as plt
import matplotlib
from matplotlib.colors import LinearSegmentedColormap
import matplotlib.patches as patches
plt.style.use('neuron_color')
import os
import sys
sys.path.append('../')
from Linearity import Neuron
import lmfit
from pickle import dump
```

```python
import sympy
sympy.__version__
```

    '1.0'

```python
def simpleaxis(axes, every=False, outward=False, hideTitle=True):
    if not isinstance(axes, (list, numpy.ndarray)):
        axes = [axes]
    for ax in axes:
        ax.spines['top'].set_visible(False)
        ax.spines['right'].set_visible(False)
        if (outward):
            ax.spines['bottom'].set_position(('outward', 10))
            ax.spines['left'].set_position(('outward', 10))
        if every:
            ax.spines['bottom'].set_visible(False)
            ax.spines['left'].set_visible(False)
        ax.get_xaxis().tick_bottom()
        ax.get_yaxis().tick_left()
        if hideTitle:
            ax.set_title('')
```

```python
from IPython.display import display, Markdown, Image
```

```python
init_printing()
```

## 6 A Circuit diagram

```python
prefix = '/home/bhalla/Documents/Codes/data'
```

## 6 B: Fitting voltage clamp data to get parameters

```python
analysisFile = prefix + '/media/sahil/NCBS_Shares_BGStim/patch_data/170530/c1_EI/plots/c1_EI.pkl'
plotDir = os.path.dirname(analysisFile)
neuron = Neuron.load(analysisFile)
```

$g(t) = \bar{g}\frac{( e^\frac{\delta_{onset} - t }{\tau_{decay}} - e^\frac{\delta_{onset} - t }{\tau_{rise}})}{- \left(\frac{\tau_{rise}}{\tau_{decay}}\right)^{\frac{\tau_{decay}}{\tau_{decay} - \tau_{rise}}} + \left(\frac{\tau_{rise}}{\tau_{decay}}\right)^{\frac{\tau_{rise}}{\tau_{decay} - \tau_{rise}}}}$

```python
def fitFunctionToPSP(time, vector, t_0=0, g_max=0):
    ''' Fits using lmfit '''

    def _doubleExponentialFunction(t, t_0, tOn, tOff, g_max):
        ''' Returns the shape of an EPSP as a double exponential function '''
        tPeak = t_0 + float(((tOff * tOn)/(tOff-tOn)) * numpy.log(tOff/tOn))
        A = 1./(numpy.exp(-(tPeak-t_0)/tOff) - numpy.exp(-(tPeak-t_0)/tOn))
        g = [ g_max * A * (numpy.exp(-(t_point-t_0)/tOff) - numpy.exp(-(t_point-t_0)/tOn)) if  t_point >= t_0 else 0. for t_point in t]
        return numpy.array(g)

    model = lmfit.Model(_doubleExponentialFunction)
    # Fixing values of variables from data
    # Onset time
    if not t_0:
        model.set_param_hint('t_0', value =max(time)/10., min=0., max = max(time))
    else:
        model.set_param_hint('t_0', value = t_0, vary=False)
    # g_max
    if not g_max:
        model.set_param_hint('g_max', value = max(vector)/10., min = 0., max = max(vector))
    else:
        model.set_param_hint('g_max', value = g_max, vary=False)

    model.set_param_hint('tOn', value =max(time)/5.1 , min = 0., max = max(time))
    model.set_param_hint('t_ratio', value =10., min=1.05)
    model.set_param_hint('tOff', min = 0., expr='tOn*t_ratio')
    model.set_param_hint('t_peak', expr = 't_0 + ((tOff * tOn)/(tOff-tOn)) * log(tOff/tOn)')
    pars = model.make_params()

    result = model.fit(vector, pars, t=time)
    # print (result.fit_report())
    return result
```

```python
n = {key:value for key,value in neuron}
for numSq in set(n[1]).intersection(set(n[2])):
    for i in set(n[1][numSq].trial).intersection(set(n[2][numSq].trial)):
        if i == 3 and numSq == 7:
            exc = -1e9*n[1][numSq].trial[i].interestWindow
            inh = 1e9*n[2][numSq].trial[i].interestWindow
            time = numpy.arange(len(n[1][numSq].trial[i].interestWindow))*n[1][numSq].trial[i].samplingTime
            exc_fit = fitFunctionToPSP(time, exc)
            inh_fit = fitFunctionToPSP(time, inh)
            print (exc_fit.fit_report())
            print (inh_fit.fit_report())
            fig,ax = plt.subplots()
            ax.plot(time*1e3, exc, alpha=0.6, c='indigo')
            ax.set_xlabel("Time (ms)")
            ax.set_ylabel("Current (pA)")
            ax.plot(time*1e3, exc_fit.best_fit, label="Excitation", c='indigo')

            ax.plot(time*1e3, -inh, alpha=0.6, c='k')
            ax.plot(time*1e3, -inh_fit.best_fit, label="Inhibition", c='k')
            ax.annotate('Excitation', (50,100), (50,100), xycoords='data',color='indigo')
            ax.annotate('Inhibition', (50,-300), (50,-300), xycoords='data',color='k')
            fig.set_figwidth(1.5)
            fig.set_figheight(1.5)
            simpleaxis(ax)
            dump(fig,file('figures/fig6/6b.pkl','wb'))
            plt.show()
```

```python
samplingRate = 20  # kHz, to get milliseconds
sample_every = 10 # points
timeStep, maxTime = (sample_every*1.)/ samplingRate, 100.  # ms
trange = numpy.arange(
    0., maxTime, timeStep)  # We will always use 100. ms timecourse of PSPs.
```

```python
#### Range of $g_e$ explored
emin = 0.01
emax = 3.
e_step = 0.5
erange = numpy.arange(emin, emax, e_step)
#### Range of proportionality ($P$) between $E$ and $I$
prop_array = numpy.arange(0, 6, 1)
```

```python
## Setting up the variables, parameters and units for simulation
t, P, e_r, e_d, delta_e, rho_e, g_e, i_r, i_d, delta_i, rho_i, g_i, b, Cm, g_L = symbols(
    't P \\tau_{er} \\tau_{ed} \\delta_e \\rho_e \\bar{g}_e \\tau_{ir} \\tau_{id} \\delta_i \\rho_i \\bar{g}_i \\beta C_m \\bar{g}_L',
    positive=True,
    real=True)
leak_rev, e_rev, i_rev, Vm = symbols(
    'Leak_{rev} Exc_{rev} Inh_{rev} V_m', real=True)
SymbolDict = {
    t: "Time (ms)",
    P: "Proportion of $g_i/g_e$",
    e_r: "Excitatory Rise (ms)",
    e_d: "Excitatory Fall (ms)",
    delta_e: "Excitatory onset time (ms)",
    rho_e: "Excitatory $tau$ ratio (fall/rise)",
    g_e: "Excitatory max conductance",
    i_r: "Inhibitory Rise (ms)",
    i_d: "Inhibitory Fall(ms)",
    delta_i: "Inhibitory onset time(ms)",
    rho_i: "Inhibitory $tau$ ratio (fall/rise)",
    g_i: "Inhibitory max conductance",
    b: "Inhibitory/Excitatory $tau$ rise ratio"
}
unitsDict = {
    's': seconds,
    'exp': exp,
    'S': siemens,
    'V': volts,
    'A': amperes,
    'm': meters,
    'kg': kg
}  # This is for lamdify
nS, pF, mV, pA = nano * siemens, pico * farads, milli * volts, pico*amperes
### Estimates from data and averaging them to get a number
estimateDict = {
    P: (1,5),
    #e_r: (1.5 * ms, 5 * ms),
    #e_d: (8. * ms, 20. * ms),
    e_r: (17. * ms, 17. * ms),
    e_d: (18. * ms, 18. * ms),
    delta_e: (0. * ms, 0. * ms),
    rho_e: (2., 7.),
    g_e: (0.02 * nS, 0.25 * nS),
    #i_r: (1.5 * ms, 5. * ms),
    #i_d: (14. * ms, 60. * ms),
    i_r: (12. * ms, 12. * ms),
    i_d: (49. * ms, 49. * ms),
    delta_i: (2. * ms, 4. * ms),
    rho_i: (5., 20.),
    g_i: (0.04 * nS, 0.5 * nS),
    b: (0.5, 5.)
}
averageEstimateDict = {
    key: value[0] + value[1] / 2
    for key, value in estimateDict.items()
}

### Approximating the rest from literature
approximateDict = {
    g_L: 10 * nS,
    e_rev: 0. * mV,
    i_rev: -70. * mV,
    leak_rev: -45. * mV,
    Cm: 100 * pF
}
sourceDict = {
    g_L: "None",
    e_rev: "None",
    i_rev: "None",
    leak_rev: "None",
    Cm: "Neuroelectro.org"
}
```

| Variable  |  Meaning |  Range |
|---|---|---|
|$t$|Time (ms)|0-100|
|$P$|Proportion of $g_i/g_e$|2-4|
|$\tau_{er}$|Excitatory Rise (ms)|1.5-5|
|$\tau_{ed}$|Excitatory Fall (ms)|8-20|
|$\delta_e$|Excitatory onset time (ms)|0-0|
|$\rho_e$|Excitatory $tau$ ratio (fall/rise)|2-7|
|$\bar{g}_e$|Excitatory max conductance|0.02-0.25|
|$\tau_{ir}$|Inhibitory Rise (ms)|1.5-5|
|$\tau_{id}$|Inhibitory Fall(ms)|14-60|
|$\delta_i$|Inhibitory onset time(ms)|3-15|
|$\rho_i$|Inhibitory $tau$ ratio (fall/rise)|5-20|
|$\bar{g}_i$|Inhibitory max conductance|0.04-0.5|
|$\beta$|Inhibitory/Excitatory $tau$ rise ratio|0.5-5|

| Variable  |  Meaning | Source | Value |
|---|---|---|
|$g_L$|Leak conductance| Fernandos and White, J. Neuro. (2010) | 10 nS |
|$Exc_{rev}$|Excitatory reversal|Calculated (Methods)| 0 mV|
|$Inh_{rev}$|Inhibitory reversal |Calculated (Methods)| -70 mV |
|$Leak_{rev}$|Leak reversal |Fernandos and White, J. Neuro. (2010)| -65 mV |
|$C_m$|Membrane capacitance |neuroelectro.org| 100 pF|

---

```python
### Double exponential to explain the net synaptic conductance.
alpha = exp(-(t - delta_e) / e_d) - exp(-(t - delta_e) / e_r)
alpha_prime = alpha.diff(t)
theta_e = solve(alpha_prime, t)  # Time to peak
theta_e = logcombine(theta_e[0])
simplify(theta_e.subs(averageEstimateDict))
alpha_star = simplify(alpha.subs(t, theta_e).doit())

### Finding maximum of the curve and substituting ratio of taus
g_E = Piecewise((0. * nS, t / ms < delta_e / ms), (g_e * (alpha / alpha_star),
                                                   True))
### Final equation for Excitation normalized to be maximum at $g_e$

### Doing the same with inhibition
g_I = g_E.xreplace({
    g_e: g_i,
    rho_e: rho_i,
    e_r: i_r,
    e_d: i_d,
    delta_e: delta_i
})
alpha_I = alpha.xreplace({e_r: i_r, e_d: i_d, delta_e: delta_i})
alpha_star_I = alpha_star.xreplace({e_r: i_r, e_d: i_d})
g_I = Piecewise((0. * nS, t / ms < delta_i / ms),
                (g_i * (alpha_I / alpha_star_I), True))
```

```python
### Now finding the control peak using difference of these double-exponentials
compartment = Eq((1 / Cm) * (g_E * (Vm - e_rev) + g_I * (Vm - i_rev) + g_L *
                             (Vm - leak_rev)), Vm.diff(t))
Vm_t = solve(compartment, Vm, rational=False, simplify=True)
check_vm_t = Vm_t[0].subs({ i: averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e,g_i, P] }).subs(approximateDict).subs({ g_i: P * g_e })
```

```python
f = lambdify((g_e, P, t), check_vm_t/mV, (unitsDict, "numpy"))
```

```python
f(1*nS, 2, 3*ms)
```

```python
g_E
```

## 6 C Divisive Inhibition: Inhibition proportional to Excitation, or $g_i = P \times g_e$

```python
di_exc =  [[float(f(e * nS, 0., dt * ms)) for dt in trange] for e in erange]
di_control = {prop: [[float(f(e * nS, prop, dt * ms)) for dt in trange] for e in erange] for prop in prop_array}
```

```python
fig, ax = plt.subplots()
# plt.style.context('neuron-color')
handles, labels = [], []
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(di_control[prop], di_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, v_max, s=10))
    ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Control  $V_{max}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, di_control[prop][5])
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6c.pkl','wb'))
# ax.set_title("Divisive Inhibition")
plt.show()
```

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    ttp, e_max = [], []
    for con_trace,e_t in zip(di_control[prop], di_exc):
        ttp.append(numpy.argmax(con_trace))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max[1:], ttp[1:], s=10))
    ax.plot(e_max[1:], ttp[1:], '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Time to peak  $t_{peak}$")
ax.set_xlim(0,15)
ax.set_ylim(0,55)
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
# dump(fig,file('figures/fig6/6g.pkl','wb'))
plt.show()
```

```python
handles, labels = [], []
for prop in prop_array:
    fig, ax = plt.subplots()
    ttp, e_max = [], []
    for con_trace,e_t in zip(di_control[prop], di_exc):
        ax.plot(trange, con_trace,c='k')
    fig.set_figwidth(12)
    plt.show()

```

```python
threshold = 5.5
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max, spk_t = [], [], []
    for con_trace,e_t in zip(di_control[prop], di_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
        spiking = numpy.where((numpy.array(con_trace) - float(approximateDict[leak_rev]/mV)) > threshold)[0]
        if len(spiking):
            spk_t.append(spiking[0])
        else:
            spk_t.append(numpy.nan)
#         print(numpy.where(e_t>threshold))
    handles.append(ax.plot(erange, spk_t, '.-'))
#     ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Spike Time  $t_{sp}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, dn_control[prop][5])
# ax.hlines(y=threshold, linestyle='--')
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='right')
fig.set_figwidth(2)
fig.set_figheight(2)
simpleaxis(ax)
#dump(fig,file('figures/fig6/6e.pkl','wb'))
# ax.set_title("Divisive Normalization", fontsize=18)
plt.show()
```

```python
print ( "Constant $delta_i$ was {:.1f} ms".format(averageEstimateDict[delta_i]/ms))
```

    Constant $delta_i$ was 4.0 ms

6 DEF: Divisive Normalization: Inhibition proportional to Excitation, or $g_i = P \times g_e$ and $\delta_i$ inversely proportional to $g_e$

## 6 D Changing $\delta_i$ = $\delta_{min} + me^{-k\times{g_e}}$

```python
time_erange = numpy.linspace(0.01,4.,10)
```

```python
d = lambda minDelay,k,e: minDelay + m*exp(-(k*e))
nS = nano*siemens
k, m, minDelay = 1.43/nS, 18.15*ms, 2.54*ms
maxDelay = (minDelay + m)/ms
```

```python
d = lambda minDelay,k,e: minDelay + (k/e)
nS = nano*siemens
k, m, minDelay = 1.5*ms*nS, -1.13, 1.5*ms
maxDelay = (minDelay + m)/ms
```

```python
fig, ax = plt.subplots()
ax.scatter(time_erange, [d(minDelay,k,e*nS)/ms for e in time_erange], s=40, facecolor='k', edgecolor='k')
ax.set_xlabel("$g_{exc}$ (nS)")
ax.set_ylabel("$\\delta_i$ (ms)")
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
ax.set_xlim(0,4.5)
ax.set_ylim(0, 13 )
ax.set_xticks(range(4))
ax.set_yticks(range(0,13,2))
simpleaxis(ax)
dump(fig,file('figures/fig6/6d.pkl','wb'))
plt.show()
```

```python
check_vm = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i]}).subs(approximateDict).subs({g_i: P*g_e, delta_i: d(minDelay,k,g_e)}).evalf())
f = lambdify((g_e, P, t), check_vm/mV, (unitsDict, "numpy"))
```

```python
dn_exc =  [[float(f(e * nS, 0., dt * ms)) for dt in trange] for e in erange]
```

```python
dn_control = {prop: [[float(f(e * nS, prop, dt * ms)) for dt in trange] for e in erange] for prop in prop_array}
```

## 6 E Divisive Normalization

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, v_max, s=10))
    ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Control  $V_{max}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, dn_control[prop][5])
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6e.pkl','wb'))
# ax.set_title("Divisive Normalization", fontsize=18)
plt.show()
```

### Tau changes

```python
getTauFall = lambda tau_prop, e: tau_prop*e
ms = milli*seconds
nS = nano * siemens
tau_prop = 2e3 *ms/nS
```

```python
check_vm = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i, i_d]}).subs(approximateDict).subs({g_i: P*g_e, delta_i: d(minDelay,k,g_e), i_d: getTauFall(tau_prop,g_e)}).evalf())
```

```python
simplify(check_vm)
```

```python
f = lambdify((g_e, P, t), check_vm/mV, (unitsDict, "numpy"))
```

```python
dn_exc =  [[float(f(e * nS, 0., dt * ms)) for dt in trange] for e in erange]
```

```python
for prop in prop_array:
    print(prop)
    for e in erange:
        print(e)
        #tau_prop = 2e3

        try:
            dt = 50
            print (f(e * nS, prop, dt*ms))#plt.plot([float(f(e * nS, prop, dt * ms).evalf()) for dt in trange])
            print("TRY")
        except:
            dt = 50
            print("EXCEPT")
            print (f(e * nS, prop, dt*ms))#plt.plot([float(f(e * nS, prop, dt * ms).evalf()) for dt in trange])
        #simpleaxis(ax)
        #plt.show()
```

    0
    0.01
    -44.9653566348278
    TRY
    0.51
    -43.2986767780553
    TRY
    1.01
    -41.7511348339267
    TRY
    1.51
    -40.3103972598019
    TRY
    2.01
    -38.9657761373041
    TRY
    2.51
    -37.7079635691310
    TRY
    1
    0.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 6.24057394448034e-13*A**2.0*s**3.0)/(4.53044977040458e-7*A**2*s**3 + 4.03583443646615e-10*A**2.0*s**3.0)
    TRY
    0.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.30700553193618e-11*A**2.0*s**3.0)/(4.70483868794951e-7*A**2*s**3 + 2.13866976436948e-8*A**2.0*s**3.0)
    TRY
    1.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 6.60942261455351e-11*A**2.0*s**3.0)/(4.87922760549444e-7*A**2*s**3 + 4.27437213792911e-8*A**2.0*s**3.0)
    TRY
    1.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 9.91959121002961e-11*A**2.0*s**3.0)/(5.05361652303937e-7*A**2*s**3 + 6.41508748350197e-8*A**2.0*s**3.0)
    TRY
    2.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.32174129191874e-10*A**2.0*s**3.0)/(5.2280054405843e-7*A**2*s**3 + 8.54781798834868e-8*A**2.0*s**3.0)
    TRY
    2.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.65018747047315e-10*A**2.0*s**3.0)/(5.40239435812923e-7*A**2*s**3 + 1.06719085122788e-7*A**2.0*s**3.0)
    TRY
    2
    0.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.24811478889607e-12*A**2.0*s**3.0)/(4.53044977040458e-7*A**2*s**3 + 8.07166887293229e-10*A**2.0*s**3.0)
    TRY
    0.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 6.61401106387236e-11*A**2.0*s**3.0)/(4.70483868794951e-7*A**2*s**3 + 4.27733952873896e-8*A**2.0*s**3.0)
    TRY
    1.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.3218845229107e-10*A**2.0*s**3.0)/(4.87922760549444e-7*A**2*s**3 + 8.54874427585823e-8*A**2.0*s**3.0)
    TRY
    1.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.98391824200592e-10*A**2.0*s**3.0)/(5.05361652303937e-7*A**2*s**3 + 1.28301749670039e-7*A**2.0*s**3.0)
    TRY
    2.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 2.64348258383749e-10*A**2.0*s**3.0)/(5.2280054405843e-7*A**2*s**3 + 1.70956359766974e-7*A**2.0*s**3.0)
    TRY
    2.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.3003749409463e-10*A**2.0*s**3.0)/(5.40239435812923e-7*A**2*s**3 + 2.13438170245576e-7*A**2.0*s**3.0)
    TRY
    3
    0.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.8721721833441e-12*A**2.0*s**3.0)/(4.53044977040458e-7*A**2*s**3 + 1.21075033093984e-9*A**2.0*s**3.0)
    TRY
    0.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 9.92101659580854e-11*A**2.0*s**3.0)/(4.70483868794951e-7*A**2*s**3 + 6.41600929310843e-8*A**2.0*s**3.0)
    TRY
    1.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.98282678436605e-10*A**2.0*s**3.0)/(4.87922760549444e-7*A**2*s**3 + 1.28231164137873e-7*A**2.0*s**3.0)
    TRY
    1.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 2.97587736300888e-10*A**2.0*s**3.0)/(5.05361652303937e-7*A**2*s**3 + 1.92452624505059e-7*A**2.0*s**3.0)
    TRY
    2.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.96522387575623e-10*A**2.0*s**3.0)/(5.2280054405843e-7*A**2*s**3 + 2.56434539650461e-7*A**2.0*s**3.0)
    TRY
    2.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 4.95056241141945e-10*A**2.0*s**3.0)/(5.40239435812923e-7*A**2*s**3 + 3.20157255368364e-7*A**2.0*s**3.0)
    TRY
    4
    0.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 2.49622957779214e-12*A**2.0*s**3.0)/(4.53044977040458e-7*A**2*s**3 + 1.61433377458646e-9*A**2.0*s**3.0)
    TRY
    0.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.32280221277447e-10*A**2.0*s**3.0)/(4.70483868794951e-7*A**2*s**3 + 8.55467905747791e-8*A**2.0*s**3.0)
    TRY
    1.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 2.6437690458214e-10*A**2.0*s**3.0)/(4.87922760549444e-7*A**2*s**3 + 1.70974885517165e-7*A**2.0*s**3.0)
    TRY
    1.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.96783648401184e-10*A**2.0*s**3.0)/(5.05361652303937e-7*A**2*s**3 + 2.56603499340079e-7*A**2.0*s**3.0)
    TRY
    2.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 5.28696516767498e-10*A**2.0*s**3.0)/(5.2280054405843e-7*A**2*s**3 + 3.41912719533947e-7*A**2.0*s**3.0)
    TRY
    2.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 6.6007498818926e-10*A**2.0*s**3.0)/(5.40239435812923e-7*A**2*s**3 + 4.26876340491152e-7*A**2.0*s**3.0)
    TRY
    5
    0.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.12028697224017e-12*A**2.0*s**3.0)/(4.53044977040458e-7*A**2*s**3 + 2.01791721823307e-9*A**2.0*s**3.0)
    TRY
    0.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 1.65350276596809e-10*A**2.0*s**3.0)/(4.70483868794951e-7*A**2*s**3 + 1.06933488218474e-7*A**2.0*s**3.0)
    TRY
    1.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 3.30471130727676e-10*A**2.0*s**3.0)/(4.87922760549444e-7*A**2*s**3 + 2.13718606896456e-7*A**2.0*s**3.0)
    TRY
    1.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 4.9597956050148e-10*A**2.0*s**3.0)/(5.05361652303937e-7*A**2*s**3 + 3.20754374175099e-7*A**2.0*s**3.0)
    TRY
    2.01
    -45269.6199205368*(4.5e-10*A**2*s**3 + 6.60870645959372e-10*A**2.0*s**3.0)/(5.2280054405843e-7*A**2*s**3 + 4.27390899417434e-7*A**2.0*s**3.0)
    TRY
    2.51
    -45269.6199205368*(4.5e-10*A**2*s**3 + 8.25093735236576e-10*A**2.0*s**3.0)/(5.40239435812923e-7*A**2*s**3 + 5.3359542561394e-7*A**2.0*s**3.0)
    TRY

```python
dn_control = {prop: [[float(f(e * nS, prop, dt * ms)) for dt in trange] for e in erange] for prop in prop_array}
```

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, v_max, s=10))
    ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Control  $V_{max}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, dn_control[prop][5])
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
#dump(fig,file('figures/fig6/6e.pkl','wb'))
# ax.set_title("Divisive Normalization", fontsize=18)
plt.show()
```

### Synapses to threshold

```python
threshold = 5.5
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max, spk_t = [], [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
        spiking = numpy.where((numpy.array(con_trace) - float(approximateDict[leak_rev]/mV)) > threshold)[0]
        if len(spiking):
            spk_t.append(spiking[0])
        else:
            spk_t.append(numpy.nan)
#         print(numpy.where(e_t>threshold))
    handles.append(ax.plot(erange, spk_t, '.-'))
#     ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Spike Time  $t_{sp}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, dn_control[prop][5])
# ax.hlines(y=threshold, linestyle='--')
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='right')
fig.set_figwidth(2)
fig.set_figheight(2)
simpleaxis(ax)
#dump(fig,file('figures/fig6/6e.pkl','wb'))
# ax.set_title("Divisive Normalization", fontsize=18)
plt.show()
```

```python
fig, ax = plt.subplots()
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    e_max = numpy.array(e_max)
    v_max = numpy.array(v_max)
    handles.append(ax.scatter(erange, e_max/v_max, s=10))
    ax.plot(erange, e_max/v_max, '--')
ax.set_xlabel("Excitation $g_{exc}$")
ax.set_ylabel("Gain")
fig.set_figwidth(2)
fig.set_figheight(2)
simpleaxis(ax)
plt.show()
```

## 5 B Model subtraction scheme

```python
fig, ax = plt.subplots()
handles, labels = [], []
prop = 4

i_max, e_max = [], []
trace_c, trace_e = numpy.array(dn_control[prop][-1]), numpy.array(dn_exc[-1])
ax.plot(trange, trace_c, label="PSP")
ax.plot(trange, trace_e, label="EPSP")
trace_i =  float(approximateDict[leak_rev]/mV) + (trace_c - trace_e)
ax.plot(trange, trace_i, label="Derived IPSP")
ax.set_xlabel("Time")
ax.set_ylabel("$V_m$")
fig.set_figwidth(3)
fig.set_figheight(3)
simpleaxis(ax)
dump(fig,file('figures/fig5/5b.pkl','wb'))
plt.legend()
plt.show()
```

## 6 F Excitation - Derived Inhibition plot

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    i_max, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        i_t = numpy.array(e_t) - numpy.array(con_trace)
        i_max.append(numpy.max(i_t))
#         i_max.append(max(e_t) - max(con_trace))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, i_max, s=10))
    ax.plot(e_max, i_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Derived Inhibition  $V_{max}$")
xlim = ax.get_xlim()
ax.set_ylim (xlim)
ax.plot(xlim, xlim, '--')
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6f.pkl','wb'))
plt.show()
```

## 6 G Time to peak

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    ttp, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        ttp.append(numpy.argmax(con_trace))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max[1:], ttp[1:], s=10))
    ax.plot(e_max[1:], ttp[1:], '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Time to peak  $t_{peak}$")
ax.set_xlim(0,15)
ax.set_ylim(0,55)
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6g.pkl','wb'))
plt.show()
```

```python
handles, labels = [], []
for prop in prop_array:
    fig, ax = plt.subplots()
    ttp, e_max = [], []
    for con_trace,e_t in zip(dn_control[prop], dn_exc):
        ax.plot(trange, con_trace,c='k')
    fig.set_figwidth(12)
    plt.show()
```

## 6 H Permutation of P

```python
check_vm = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i]}).subs(approximateDict).subs({delta_i: d(minDelay,k,g_e)}).evalf())
f = lambdify((g_e, g_i, t), check_vm/mV, (unitsDict, "numpy"))
```

```python
p_perm_dn_exc =  [[float(f(e * nS, 0., dt * ms)) for dt in trange] for e in erange]
p_perm_dn_control = {prop: [[float(f(e * nS, i * nS, dt * ms)) for dt in trange] for (e,i) in zip(erange, numpy.random.permutation(erange*prop))] for prop in prop_array}
```

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(p_perm_dn_control[prop], p_perm_dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, v_max, s=10))
    ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Control  $V_{max}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, p_perm_dn_control[prop][5])
#ax2.set_xlabel("Time")
#ax2.set_ylabel("Membrane potential (mV)")
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6h.pkl','wb'))
# ax.set_title("Divisive Normalization with E and I balance permuted", fontsize=18)
plt.show()
```

## 6 I Permutation of $\delta_i$

```python
check_vm = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i]}).subs(approximateDict).subs({g_i: P*g_e}).evalf())
f = lambdify((g_e, P, delta_i, t), check_vm/mV, (unitsDict, "numpy"))
```

```python
d_perm_dn_exc =  [[float(f(e * nS, 0., d(minDelay,k, e* nS), dt * ms)) for dt in trange] for e in erange]
d_perm_dn_control = {prop: [[float(f(e * nS, prop, delay, dt * ms)) for dt in trange] for e,delay in zip(erange, numpy.random.permutation([d(minDelay,k, e* nS) for e in erange])) ] for prop in prop_array}
```

```python
fig, ax = plt.subplots()
handles, labels = [], []
for prop in prop_array:
    v_max, e_max = [], []
    for con_trace,e_t in zip(d_perm_dn_control[prop], d_perm_dn_exc):
        v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
        e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
    handles.append(ax.scatter(e_max, v_max, s=10))
    ax.plot(e_max, v_max, '--')
    labels.append("$P= {}$".format(prop))
ax.set_xlabel("Excitation $V_{max}$")
ax.set_ylabel("Control  $V_{max}$")
# left, bottom, width, height = [0.25, 0.6, 0.2, 0.2]
# ax2 = fig.add_axes([left, bottom, width, height])
# for prop in prop_array:
#     ax2.plot(trange, d_perm_dn_control[prop][5])
# fig.legend(handles, labels, loc ='center right')
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
dump(fig,file('figures/fig6/6i.pkl','wb'))
# ax.set_title("Divisive Normalization", fontsize=18)
plt.show()
```

## 6 J Phase plot Divisive Normalization

```python
import lmfit
def DN_model(x,a=1):
    # Divisive normalization model
    return (a*x)/(x+a)
DN_Model = lmfit.Model(DN_model)
```

```python
check_vm = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i]}).subs(approximateDict).subs({g_i: P*g_e}).evalf())
f = lambdify((g_e, P, delta_i, t), check_vm/mV, (unitsDict, "numpy"))
```

```python
inhib = simplify(Vm_t[0].subs({i:averageEstimateDict[i] for i in averageEstimateDict if i not in [g_e, g_i, delta_i]}).subs(approximateDict).evalf())
g = lambdify((g_e, g_i, delta_i, t), inhib/mV, (unitsDict, "numpy"))
```

```python
phase_dn_control = {}
phase_dn_exc = {}
phase_dn_inh = {}

# prop_array = numpy.logspace(-1,1,7)
# k_array = numpy.logspace(-1,1,7)

prop_array = numpy.linspace(0,6,7)
k_array = numpy.linspace(0.,3.,7)
```

```python
for k in k_array:
    phase_dn_exc[k] = [[float(f(e * nS, 0., d(minDelay,k/nS, e* nS), dt * ms)) for dt in trange] for e in erange]
    phase_dn_control[k] = {prop: [[float(f(e * nS, prop, delay, dt * ms)) for dt in trange] for e,delay in zip(erange, [d(minDelay,k/nS, e* nS) for e in erange]) ] for prop in prop_array}
#     phase_dn_inh[k] = {prop: [[float(g(0 * nS, prop*e, delay, dt * ms)) for dt in trange] for e,delay in zip(erange, [d(minDelay,k/nS, e* nS) for e in erange]) ] for prop in prop_array}
```

```python
phase_dn_inh = {}
for k in k_array:
    phase_dn_inh[k] = {prop: [[float(g(0 * nS, prop*e* nS, delay, dt * ms)) for dt in trange] for e,delay in zip(erange, [d(minDelay,k/nS, e* nS) for e in erange]) ] for prop in prop_array}
```

```python
phaseMat_init = numpy.zeros((len(k_array),len(prop_array)))

for ind1, k in enumerate(k_array):
    for ind2, prop in enumerate(prop_array):
        v_max, e_max = [], []
        for con_trace,e_t in zip(phase_dn_control[k][prop], phase_dn_exc[k]):
            v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
            e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
        X, y = e_max, v_max
        DN_pars = DN_Model.make_params()
        DN_result = DN_Model.fit(y, DN_pars, x=X)

#         plt.plot(X, y, 'bo')
#         plt.plot(X, DN_result.best_fit, 'r-')
#         plt.xlim(0,1.2*max(e_max))
#         plt.ylim(0,1.2*max(e_max))
#         plt.show()
        phaseMat_init[ind1][ind2] = DN_result.params['a']
#         print(DN_result.fit_report())

# x,y = numpy.meshgrid(prop_array, k_array)

#cmap = LinearSegmentedColormap.from_list('gamma_purple', [(0.,'purple' ), (1., 'white')])
cmap = matplotlib.cm.inferno_r
cmap.set_bad(color='white')

print ("Max gamma is {}".format(numpy.max(phaseMat_init)))
gamma_cutOff = 40
cutOffmask = numpy.ma.masked_where(phaseMat_init > gamma_cutOff, phaseMat_init)
phaseMat = numpy.ma.masked_where(numpy.isnan(phaseMat_init), cutOffmask)

vmax = numpy.nanmax(phaseMat)
vmin = numpy.nanmin(phaseMat)

fig, ax = plt.subplots()

phaseMat
#heatmap = ax.pcolormesh(phaseMat, norm=matplotlib.colors.LogNorm(vmin=vmin, vmax=vmax), cmap = cmap, edgecolor='k', linewidths=.05)
heatmap = ax.pcolormesh(phaseMat, vmin=0, vmax=gamma_cutOff, cmap = cmap, edgecolor='k', linewidths=.05)
# ax.grid(True, which='minor', axis='both', linestyle='--', alpha=0.1, color='k')

ax.invert_yaxis()
ticks = numpy.arange(0,len(prop_array),2)
ax.xaxis.set_ticks(ticks+0.5)
ax.yaxis.set_ticks(ticks+0.5)

ax.yaxis.set(ticklabels=["{:.0f}".format(j) for j in k_array[ticks]])
ax.xaxis.set(ticklabels=["{:.0f}".format(j) for j in prop_array[ticks]])

# ax.axis([int(k_array.min()),int(k_array.max()),int(prop_array.min()),int(prop_array.max())])
# for axis in [ax.xaxis, ax.yaxis]:
#     axis.set_ticks([0,10,10], minor=True)
#     axis.set(ticks=[0,10,10], ticklabels=numpy.linspace(0,10,10)) #Skipping square labels

# ax.set_xlim((-1,1))
# ax.set_ylim((-1,1))

#Colorbar stuff
cbar = plt.colorbar(heatmap, label = "$\\gamma$", ticks=[0,20,40])
cbar.ax.get_yaxis().labelpad = 6
# tick_locator = matplotlib.ticker.MaxNLocator(nbins=5)
# cbar.locator = tick_locator
# cbar.update_ticks()

# ax.patch.set(hatch='xx', edgecolor='purple')

simpleaxis(ax,every=True,outward=False)
ax.set_aspect(1)
fig.set_figwidth(2.)
fig.set_figheight(2.)

ax.set_ylabel("K")
ax.set_xlabel("I/E")
# ax.set_title("Divisive Normalization", fontsize=18)

dump(fig,file('figures/supplementary/11a.pkl','wb'))
plt.show()
```

```python
print (k_array)
```

### Delay plots

```python
d = lambda minDelay,k,e: minDelay + m*exp(-(k*e))
nS = nano*siemens
m, minDelay = 18.15*ms, 2.54*ms
maxDelay = (minDelay + m)/ms
```

```python
k_sample_indices = [1,3,5]
fig, ax = plt.subplots(len(k_array[k_sample_indices]),1,sharey=True)
for axis,k in zip(ax,k_array[k_sample_indices]):
    axis.plot(time_erange, [d(minDelay,k/nS,e*nS)/ms for e in time_erange], '.-', c='k', markersize=5)
    axis.set_xlim(0,4.5)
    axis.set_ylim(0, 13 )
    axis.set_xticks(range(4))
    axis.set_yticks(range(0,13,6))
    axis.set_title("k={}".format(k))
ax[0].set_ylabel("$\\delta_i$ (ms)")
ax[-1].set_xlabel("$g_{exc}$ (nS)")
simpleaxis(ax,hideTitle=False)
fig.set_figwidth(1)
fig.set_figheight(3)
dump(fig,file('figures/supplementary/11b.pkl','wb'))
plt.show()
```

### I/E differences

```python
ie_sample_indices = [1,3,6]
fig, ax = plt.subplots(1,3,sharey=True)
for axis,i_by_e in zip(ax, prop_array[ie_sample_indices]):
    axis.plot(erange, i_by_e * erange, '.-', c='k', markersize=5)
    axis.set_xlabel("$g_{exc}$ (nS)")
    axis.set_xlim(0,4.5)
    axis.set_xticks(range(4))
#     axis.set_yticks(range(0,13,2))
#     axis.set_title("I/E={}".format(i_by_e))
ax[0].set_ylabel("$g_{inh}$ (nS)")
simpleaxis(ax,hideTitle=False)
fig.set_figwidth(3)
fig.set_figheight(1)
dump(fig,file('figures/supplementary/11c.pkl','wb'))
plt.show()
```

### DN traces for these values

```python
fig, ax = plt.subplots(len(k_sample_indices), len(ie_sample_indices), sharex=True, sharey=True)
sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=0, vmax=gamma_cutOff))
for ind1,k_index in enumerate(k_sample_indices):
    for ind2,prop_index in enumerate(ie_sample_indices):
        k, prop = k_array[k_index], prop_array[prop_index]
        for trace in phase_dn_control[k][prop]:
            if phaseMat[k_index][prop_index]:
                ax[ind1][ind2].plot(trange, trace, c=sm.to_rgba(float(phaseMat[k_index][prop_index])), linewidth=1)
            else:
                ax[ind1][ind2].plot(trange, trace, c='k', linewidth=1)
#         ax[ind1][ind2].set_title("K={},I/E={}".format(k,prop))
simpleaxis(fig.get_axes(),hideTitle=False)
fig.set_figwidth(3)
fig.set_figheight(3)
dump(fig,file('figures/supplementary/11d.pkl','wb'))
plt.show()
```

### SDN curve for these values

```python
sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(vmin=0, vmax=gamma_cutOff))
fig, ax = plt.subplots(len(k_sample), len(ie_sample), sharex=True, sharey=True)
for ind1,k_index in enumerate(k_sample_indices):
    for ind2,prop_index in enumerate(ie_sample_indices):
        k, prop = k_array[k_index], prop_array[prop_index]

        obs_sdn = numpy.array([numpy.max(trace) for trace in phase_dn_control[k][prop]]) - float(approximateDict[leak_rev]/mV)
        exp_sdn = numpy.array([numpy.max(trace) for trace in phase_dn_exc[k]])  - float(approximateDict[leak_rev]/mV)

        if phaseMat[k_index][prop_index]:
            ax[ind1][ind2].plot(exp_sdn, obs_sdn, '.-', c=sm.to_rgba(float(phaseMat[k_index][prop_index])), markersize=5, linewidth=1)
            ax[ind1][ind2].set_title("$\gamma$ = " + "{:.2f}".format(phaseMat_init[k_index][prop_index]))
#             ax[ind1][ind2].set_title("K={}, I/E={}, ".format(k,prop) + "$\gamma$ = " + "{:.2e}".format(phaseMat_init[k_index][prop_index]))
        else:
            ax[ind1][ind2].plot(exp_sdn, obs_sdn, '.-', c='k', markersize=5, linewidth=1)
            #ax[ind1][ind2].set_title("$\gamma$ > 40")
#             ax[ind1][ind2].set_title("K={}, I/E={}, ".format(k,prop) + "$\gamma$ = " + "{:.2e}".format(phaseMat_init[k_index][prop_index]))

#     if phaseMat[k_index][prop_index]:
#             print (k_index, prop_index)
#             ax[ind1][ind2].set_title("$\gamma$ = " + "{:.2f}".format(phaseMat_init[k_index][prop_index]))
#         else:
#             print ("Didn't work, {},{}".format(k_index, prop_index))
#             ax[ind1][ind2].set_title("$\gamma$ > 40")
simpleaxis(fig.get_axes(),hideTitle=False)
fig.set_figwidth(3)
fig.set_figheight(3)
dump(fig,file('figures/supplementary/11e.pkl','wb'))
plt.show()
```

```python
exp_sdn, obs_sdn
```

    (array([  1.42108547e-14,   3.09511844e+00,   5.90887286e+00,
              8.47796161e+00,   1.08329669e+01,   1.29995778e+01]),
     array([  1.42108547e-14,   1.88185101e+00,   2.51450521e+00,
              3.07378708e+00,   3.55554570e+00,   3.99203815e+00]))

```python
k = k_array[4]
p = prop_array[4]

numColors = 10
cm = matplotlib.cm.viridis_r
cgen = (cm(1.*i/numColors) for i in range(numColors))
maxTime = 200

fig, ax = plt.subplots()
for con_trace,exc_trace,inh_trace in zip(phase_dn_control[k][prop][1:], phase_dn_exc[k][1:], phase_dn_inh[k][prop][1:]):
    c = cgen.next()
    ax.plot(con_trace[:maxTime], '-', linewidth=2, c=c)
    ax.plot(exc_trace[:maxTime], '-', linewidth=2, c=c)
    ax.plot( [-65 - (a - b) for a,b in zip(exc_trace[:maxTime],con_trace[:maxTime])], '-', linewidth=2, c=c)
#     ax.plot(inh_trace[:maxTime], '-', linewidth=2, c=c)
    ax.hlines(y=max(con_trace[:maxTime]), xmin=0, xmax=maxTime, linestyles='--')
#     ax.hlines(y=max(con_trace[:maxTime]))
simpleaxis(ax,every=True)
fig.set_figheight(15)
fig.set_figwidth(15)
plt.show()
```

```python
fig, ax = plt.subplots()
for inh_trace in phase_dn_inh[k][p]:
    ax.plot(inh_trace)
plt.show()
```

```python
len(phase_dn_inh[8])
```

```python
# for ind1, k in enumerate(k_array):
#     for ind2, prop in enumerate(prop_array):
#         v_max, e_max = [], []
#         for con_trace,e_t in zip(phase_dn_control[k][prop], phase_dn_exc[k]):
#             v_max.append(max(con_trace) - float(approximateDict[leak_rev]/mV))
#             e_max.append(max(e_t) - float(approximateDict[leak_rev]/mV))
#         X, y = e_max, v_max
#         DN_pars = DN_Model.make_params()
#         DN_result = DN_Model.fit(y, DN_pars, x=X)
#         print (k, prop)
#         print(DN_result.fit_report())
#         f,ax = plt.subplots()
#         DN_result.plot_fit(ax)
#         plt.show()
```

## 6 K $\delta_i$ as a function of $g_e$

```python
prefix = '/home/bhalla/Documents/Codes/data'
n = Neuron.load(prefix + '/media/sahil/NCBS_Shares_BGStim/patch_data/170720/c5_EI/plots/c5_EI.pkl')
```

```python
def delay_excitation(x, a=1., b=1., c=1.):
    # Delay as a function of excitation
#     return a + b*numpy.exp(-c*x)
    return a+(x**b)
```

```python
def findOnsetTime(trial, step=0.5, slide = 0.05, minOnset = 2., maxOnset = 50., initpValTolerance=1.0, pValMinTolerance = 0.1):
    maxIndex = int(trial.F_sample*maxOnset*1e-3)
    if expType == 1:
        maxOnsetIndex = numpy.argmax(-trial.interestWindow[:maxIndex])
    elif expType == 2:
        maxOnsetIndex = numpy.argmax(trial.interestWindow[:maxIndex])
    else:
        maxOnsetIndex = numpy.argmax(trial.interestWindow[:maxIndex])

    window_size = len(trial.interestWindow)
    step_size = int(trial.F_sample*step*1e-3)

    overlap =  int(trial.F_sample*slide*1e-3)

    index_right = maxOnsetIndex
    index_left = index_right - step_size
    minOnsetIndex = int(trial.F_sample*minOnset*1e-3)

    baseMean = numpy.mean(trial.interestWindow[:minOnsetIndex])
    factor = 5
    thresholdGradient = 0.01
    pValTolerance = initpValTolerance

    l_window = trial.interestWindow[:minOnsetIndex]
    while (index_left>minOnset):
        r_window = trial.interestWindow[index_left:index_right] #, trial.baselineWindow #trial.interestWindow[index_left - step_size:index_left]
        stat, pVal = ss.ks_2samp(r_window, l_window)
        if pVal>pValTolerance:
            return float(index_right)/trial.F_sample

        else:
            index_left-=overlap
            index_right-=overlap
            if index_left<=minOnsetIndex:
                pValTolerance/=2
                if pValTolerance<pValMinTolerance:
#                             print ("Returning Nan")
                            return numpy.nan
                else:
                    index_right = maxOnsetIndex
                    index_left = maxOnsetIndex - step_size
```

```python
# avg_exc_onset = {}
# avg_inh_onset = {}
# avg_exc_max = {}
# exc_onsets, inh_onsets = {}, {}
# exc_max,inh_max = {}, {}
# err_inh_onsets = {}
# scalingFactor = 1e6
# for expType, experiment in n:
#     for sqr in experiment:
#         for coord in experiment[sqr].coordwise:
#             if expType == 1:
#                 for trial in experiment[sqr].coordwise[coord].trials:
#                     exc_onsets[(sqr,trial.index)] = findOnsetTime(trial)*1e3
#                     exc_max[(sqr,trial.index)] = -trial.feature[5]*scalingFactor
#                     #exp[sqr].coordwise[coord].average_feature[5]
#             if expType == 2:
#                 list_inh_onset = []
#                 for trial in experiment[sqr].coordwise[coord].trials:
#                     inh_onsets[(sqr,trial.index)] = findOnsetTime(trial)*1e3
#                     list_inh_onset.append(inh_onsets[(sqr,trial.index)])
#                     inh_max[(sqr,trial.index)] = trial.feature[0]*scalingFactor
#                 avg_onset = numpy.nanmean([onset for onset in list_inh_onset if onset])
#                 err_onset = numpy.nanstd([onset for onset in list_inh_onset if onset])
#                 for trial in experiment[sqr].coordwise[coord].trials:
#                     avg_inh_onset[(sqr,trial.index)] = avg_onset
#                     err_inh_onsets[(sqr,trial.index)] = err_onset
#print (avg_exc_max, avg_exc_onset, avg_inh_onset)
```

```python
avg_exc_onset = {}
avg_inh_onset = {}
avg_exc_max = {}
exc_onsets, inh_onsets = {}, {}
exc_max,inh_max = {}, {}
err_exc_onset, err_inh_onset = {}, {}
scalingFactor = 1e6

for expType, experiment in n:
    for sqr in experiment:
        for coord in experiment[sqr].coordwise:
            if expType == 1:
                list_exc_onset = []
                list_exc_max = []
                for trial in experiment[sqr].coordwise[coord].trials:
                    onsetTime = findOnsetTime(trial)
                    if onsetTime:
                        exc_onsets[(sqr,trial.index)] = onsetTime*1e3
                        list_exc_onset.append(exc_onsets[(sqr,trial.index)])
                        list_exc_max.append(-trial.feature[5]*scalingFactor)
                    #exp[sqr].coordwise[coord].average_feature[5]
                avg_exc_onset[coord] = numpy.nanmean([onset for onset in list_exc_onset if onset])
                err_exc_onset[coord] = numpy.nanstd([onset for onset in list_exc_onset if onset])
                exc_max[coord] = numpy.nanmean([maxC for maxC in list_exc_max if maxC])
#                 for trial in experiment[sqr].coordwise[coord].trials:
#                     avg_exc_onset[(sqr,trial.index)] = avg_onset
#                     err_exc_onsets[(sqr,trial.index)] = err_onset
            if expType == 2:
                list_inh_onset = []
                for trial in experiment[sqr].coordwise[coord].trials:
                    onsetTime = findOnsetTime(trial)
                    if onsetTime:
                        inh_onsets[(sqr,trial.index)] = onsetTime*1e3
                        list_inh_onset.append(inh_onsets[(sqr,trial.index)])
                        inh_max[(sqr,trial.index)] = trial.feature[0]*scalingFactor
                avg_inh_onset[coord] = numpy.nanmean([onset for onset in list_inh_onset if onset])
                err_inh_onset[coord] = numpy.nanstd([onset for onset in list_inh_onset if onset])
#                 for trial in experiment[sqr].coordwise[coord].trials:
#                     avg_inh_onset[(sqr,trial.index)] = avg_onset
#                     err_inh_onsets[(sqr,trial.index)] = err_onset
```

```python
delay, max_current = [], []
del_err, max_err= [], []
inhibOnset = []
conductanceConversion = 70e-3
for key in set(avg_exc_onset).intersection(set(avg_inh_onset)):
    if avg_inh_onset[key] and avg_exc_onset[key]:
        if not numpy.isnan(avg_inh_onset[key]) and not numpy.isnan (avg_exc_onset[key]) and not numpy.isnan (exc_max[key]):
            delay.append(avg_inh_onset[key]- avg_exc_onset[key])
            max_current.append(exc_max[key])
#             del_err.append(err_inh_onset[key])
            inhibOnset.append(avg_inh_onset[key])
maxConductance = numpy.array(max_current)/conductanceConversion
#         del_err.append()
#         max_err.append()
```

```python
delay_Model = lmfit.Model(delay_excitation)
delay_pars = delay_Model.make_params()

delay = numpy.array(delay)
maxConductance = numpy.array(maxConductance)
# print (delay_result.params)
# print (delay_result.aic)
# print (delay_result.redchi)
```

```python
delay_result = delay_Model.fit(delay, delay_pars, x=maxConductance)
```

```python
fig, ax = plt.subplots()
ax.scatter(maxConductance, delay)
ax.set_ylim(0,)
plt.show()
```

```python
delay_result = delay_Model.fit(delay, delay_pars, x=maxConductance)
fig, ax = plt.subplots()
indices = numpy.argsort(maxConductance)
ax.scatter(maxConductance[indices], delay[indices], s=30, facecolor='k', edgecolor='k')
ax.plot(maxConductance[indices], delay_result.best_fit[indices], '-')
# print(conductance_std, delay_std)
# ax.errorbar(conductance_mean, delay_mean, xerr = conductance_std, yerr= delay_std, linestyle='',c='k')
ax.set_xticks(range(4))
ax.set_yticks(range(0,12,2))
ax.set_xlim(0,4.5)
ax.set_ylim(-3,12.5)
ax.set_xlabel("$g_e$ (nS)")
ax.set_ylabel("$\\delta_i$ (ms)")
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
# dump(fig,file('figures/fig6/6k.pkl','wb'))
plt.show()
# print ("{:.2f} + {:.2f}e^-{:.2f}E".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
print ("{:.2f} + E^-{:.2f}".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
print(delay_result.fit_report())
```

### Binning delays here

```python
bins = numpy.linspace(0,max(maxConductance),6)
digitized = numpy.digitize(maxConductance, bins)
conductance_mean = [maxConductance[digitized == i].mean() for i in range(len(bins))]
delay_mean = [delay[digitized == i].mean() for i in range(len(bins))]
conductance_std = [maxConductance[digitized == i].std(ddof=1) for i in range(len(bins))]
delay_std = [delay[digitized == i].std(ddof=1) for i in range(len(bins))]

delay_mean, conductance_mean, delay_std, conductance_std = map(list, zip(*[ (d,c,sd,sc) for d,c,sd,sc in zip(delay_mean, conductance_mean, delay_std, conductance_std) if not any(numpy.isnan([d,c,sd,sc]))]))
```

    /usr/local/lib/python2.7/dist-packages/ipykernel_launcher.py:3: RuntimeWarning: Mean of empty slice.
      This is separate from the ipykernel package so we can avoid doing imports until
    /usr/local/lib/python2.7/dist-packages/ipykernel_launcher.py:4: RuntimeWarning: Mean of empty slice.
      after removing the cwd from sys.path.

```python
print ("{:.2f} + {:.2f}e^-{:.2f}E".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
```

    -1518.52 + 1520.00e^--0.00E

```python
delay_result = delay_Model.fit(delay_mean, delay_pars, x=conductance_mean)
fig, ax = plt.subplots()
ax.scatter(conductance_mean, delay_mean, s=30, facecolor='k', edgecolor='k')
# ax.plot(conductance_mean, delay_result.best_fit, '-')
print(conductance_std, delay_std)
ax.errorbar(conductance_mean, delay_mean, xerr = conductance_std, yerr= delay_std, linestyle='',c='k')
ax.set_xticks(range(4))
ax.set_yticks(range(0,12,2))
ax.set_xlim(0,4.5)
ax.set_ylim(0,12.5)
ax.set_xlabel("$g_e$ (nS)")
ax.set_ylabel("$\\delta_i$ (ms)")
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
simpleaxis(ax)
# dump(fig,file('figures/fig6/6k.pkl','wb'))
plt.show()
print ("{:.2f} + {:.2f}e^-{:.2f}E".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
```

```python
delay_result = delay_Model.fit(delay, delay_pars, x=maxConductance)
fig, ax = plt.subplots()
ax.errorbar(numpy.array(maxConductance), numpy.array(delay), fmt ='o', markersize=2, alpha=0.4)
#ax.scatter(numpy.array(maxConductance)*1e6, numpy.array(delay)*1e3)
current_linspace= numpy.linspace(0,1.1*numpy.max(maxConductance))
ax.plot(current_linspace, delay_result.eval(x=current_linspace), '-', label="${:.2f} + {:.2f} \\times e^{{-{:.2f} \\times E }}$".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))

ax.plot(1./(delay_result.params['c'].value), delay_result.eval(x=1./(delay_result.params['c'].value)), 'ko', markersize=2)
xmin, xmax = ax.get_xlim()
ax.hlines(y=0, xmin=xmin, xmax=xmax, linestyles='--', alpha=0.5)
ax.hlines(y=delay_result.params['a'].value, xmin=xmin, xmax=xmax, linestyles='--', alpha=0.5)
ax.set_xlabel("$g_{max}^{exc}$")
ax.set_ylabel("Delay $(\\delta_{inh})$")

ax.annotate("",
            xy=(xmax, 0.), xycoords='data',
            xytext=(xmax, delay_result.params['a'].value), textcoords='data',
            arrowprops=dict(arrowstyle="<->",
                            connectionstyle="arc3"),
            )
ax.text(1.01*xmax, 1., "$\\delta_{min}$")

ax.annotate("",
            xy=(0, 0), xycoords='data',
            xytext=(0, delay_result.params['b'].value + delay_result.params['a'].value), textcoords='data',
            arrowprops=dict(arrowstyle="<->",
                            connectionstyle="arc3"),
            )
ax.text(xmin*1.5, 10., "$\\delta_{max}$")

ax.annotate("",
            xy=(xmax, delay_result.params['a'].value), xycoords='data',
            xytext=(xmax,  delay_result.params['b'].value + delay_result.params['a'].value), textcoords='data',
            arrowprops=dict(arrowstyle="<->",
                            connectionstyle="arc3"),
            )
ax.text(1.01*xmax, 10., "$m$")

# ax.text(0.006, 6., "$k$")
ax.set_xlim(xmax= xmax*1.1)
simpleaxis(ax)
plt.legend()
fig.set_figwidth(6)
fig.set_figheight(6)
# dump(fig,file('figures/fig6/6k.pkl','wb'))
plt.show()
```

### Over all EI cells

```python
voltageClampFiles = '/media/sahil/NCBS_Shares_BGStim/patch_data/voltage_clamp_files.txt'
```

```python
with open (voltageClampFiles,'r') as r:
    dirnames = r.read().splitlines()
```

```python
a = ['161220 c2_EI',
 '170510 c2_EI',
 '170524 c3_EI',
 '170524 c1_EI',
 '170530 c2_EI',
 '170530 c1_EI',
 '170531 c2_EI',
 '170531 c4_EI',
 '170531 c1_EI',
 '170720 c5_EI',
 '170720 c3_EI',
 '170720 c4_EI',
 '170720 c2_EI']
dirnames = (['/home/bhalla/Documents/Codes/data/media/sahil/NCBS_Shares_BGStim/patch_data/' + '/'.join(j.split(' ')) + '/' for j in a])
```

```python
#Colorscheme for cells
color_cell = matplotlib.cm.plasma(numpy.linspace(0,1,len(dirnames)))
```

```python
neurons = []
for dirname in dirnames:
    cellIndex = dirname.split('/')[-2]
    filename = dirname + 'plots/' + cellIndex + '.pkl'
    neurons.append(Neuron.load(filename))
```

```python
all_delays = []
all_conductances = []
all_inh_conductances = []
scalingFactor = 1e6
for index, n in enumerate(neurons):
    avg_exc_onset = {}
    avg_inh_onset = {}
    avg_exc_max = {}
    exc_onsets, inh_onsets = {}, {}
    exc_max,inh_max = {}, {}
    err_exc_onset, err_inh_onset = {}, {}

    for expType, experiment in n:
        for sqr in experiment:
            for coord in experiment[sqr].coordwise:
                if expType == 1:
                    list_exc_onset = []
                    list_exc_max = []
                    for trial in experiment[sqr].coordwise[coord].trials:
                        onsetTime = findOnsetTime(trial)
                        if onsetTime:
                            exc_onsets[(sqr,trial.index)] = onsetTime*1e3
                            list_exc_onset.append(exc_onsets[(sqr,trial.index)])
                            list_exc_max.append(-trial.feature[5]*scalingFactor)
                        #exp[sqr].coordwise[coord].average_feature[5]
                    avg_exc_onset[coord] = numpy.nanmean([onset for onset in list_exc_onset if onset])
                    err_exc_onset[coord] = numpy.nanstd([onset for onset in list_exc_onset if onset])
                    exc_max[coord] = numpy.nanmean([maxC for maxC in list_exc_max if maxC])
    #                 for trial in experiment[sqr].coordwise[coord].trials:
    #                     avg_exc_onset[(sqr,trial.index)] = avg_onset
    #                     err_exc_onsets[(sqr,trial.index)] = err_onset
                if expType == 2:
                    list_inh_onset = []
                    list_inh_max = []
                    for trial in experiment[sqr].coordwise[coord].trials:
                        onsetTime = findOnsetTime(trial)
                        if onsetTime:
                            inh_onsets[(sqr,trial.index)] = onsetTime*1e3
                            list_inh_onset.append(inh_onsets[(sqr,trial.index)])
                            list_inh_max.append(trial.feature[0]*scalingFactor)
                    avg_inh_onset[coord] = numpy.nanmean([onset for onset in list_inh_onset if onset])
                    err_inh_onset[coord] = numpy.nanstd([onset for onset in list_inh_onset if onset])
                    inh_max[coord] = numpy.nanmean([maxC for maxC in list_inh_max if maxC])

    delay, max_conductance, max_inh_conductance = [], [], []
    inhibOnset = []
    conductanceConversion = 70e-3
    for key in set(avg_exc_onset).intersection(set(avg_inh_onset)):
        if avg_inh_onset[key] and avg_exc_onset[key]:
            if not numpy.isnan(avg_inh_onset[key]) and not numpy.isnan (avg_exc_onset[key]) and not numpy.isnan (exc_max[key]) and not numpy.isnan (inh_max[key]):
                delay.append(avg_inh_onset[key]- avg_exc_onset[key])
                max_conductance.append(exc_max[key]/conductanceConversion)
                max_inh_conductance.append(inh_max[key]/conductanceConversion)
    all_delays.append(delay)
    all_conductances.append(max_conductance)
    all_inh_conductances.append(max_inh_conductance)
    print ("Done {}".format(index))
```

    Done 0
    Done 1
    Done 2
    Done 3
    Done 4
    Done 5
    Done 6
    Done 7

    /usr/local/lib/python2.7/dist-packages/ipykernel_launcher.py:41: RuntimeWarning: Mean of empty slice
    /usr/local/lib/python2.7/dist-packages/numpy/lib/nanfunctions.py:1427: RuntimeWarning: Degrees of freedom <= 0 for slice.
      keepdims=keepdims)

    Done 8
    Done 9
    Done 10
    Done 11
    Done 12

```python
# all_delays = []
# all_conductances = []
# all_inh_conductances = []
# scalingFactor = 1e6
# for index, n in enumerate(neurons):
#     avg_exc_onset = {}
#     avg_inh_onset = {}
#     avg_exc_max = {}
#     exc_onsets, inh_onsets = {}, {}
#     exc_max,inh_max = {}, {}
#     err_inh_onsets = {}
#     for expType, experiment in n:
#         for sqr in experiment:
#             for coord in experiment[sqr].coordwise:
#                 if expType == 1:
#                     exc_onsets[(sqr,coord)] = []
#                     exc_max[(sqr,coord)] = []
#                     for trial in experiment[sqr].coordwise[coord].trials:
#                         onsetTime = findOnsetTime(trial)
#                         if onsetTime:
#                             exc_onsets[(sqr,coord)].append(onsetTime*1e3)
#                             exc_max[(sqr,coord)].append(-trial.feature[5]*scalingFactor)
#                             #exp[sqr].coordwise[coord].average_feature[5]
#                     exc_onsets[(sqr,coord)] = numpy.nanmean(exc_onsets[(sqr,coord)])
#                     exc_max[(sqr,coord)] = numpy.nanmean(exc_max[(sqr,coord)])

#                 if expType == 2:
#                     inh_onsets[(sqr,coord)] = []
#                     inh_max[(sqr,coord)] = []
#                     #list_inh_onset = []
#                     for trial in experiment[sqr].coordwise[coord].trials:
#                         onsetTime = findOnsetTime(trial)
#                         if onsetTime:
#                             inh_onsets[(sqr,coord)].append(onsetTime*1e3)
#                             #list_inh_onset.append(onsetTime*1e3)
#                             inh_max[(sqr,coord)].append(trial.feature[0]*scalingFactor)
#                     #avg_onset = numpy.nanmean([onset for onset in list_inh_onset if onset])
#                     #err_onset = numpy.nanstd([onset for onset in list_inh_onset if onset])
# #                     for trial in exp[sqr].coordwise[coord].trials:
# #                         avg_inh_onset[(sqr,trial.index)] = avg_onset
# #                         err_inh_onsets[(sqr,trial.index)] = err_onset
#                     inh_onsets[(sqr,coord)] = numpy.nanmean(inh_onsets[(sqr,coord)])
#                     inh_max[(sqr,coord)] = numpy.nanmean(inh_max[(sqr,coord)])

#     delay, max_conductance, max_inh_conductance = [], [], []
# #     del_err, max_err= [], []
#     inhibOnset = []
#     conductanceConversion = 70e-3
#     for key in set(exc_onsets).intersection(set(inh_onsets)):
#         if inh_onsets[key] and exc_onsets[key]:
# #             print ("Doing {}".format(index))
# #             print (inh_onsets[key], exc_onsets[key], exc_max[key])
#             if not numpy.isnan(inh_onsets[key]) and not numpy.isnan (exc_onsets[key]) and not numpy.isnan (exc_max[key]) and not numpy.isnan (inh_max[key]):
# #                 print ("Delay is {}".format(inh_onsets[key]- exc_onsets[key]))
#                 delay.append(inh_onsets[key]- exc_onsets[key])
#                 max_conductance.append(exc_max[key]/conductanceConversion)
#                 max_inh_conductance.append(inh_max[key]/conductanceConversion)
#     all_delays.append(delay)
#     all_conductances.append(max_conductance)
#     all_inh_conductances.append(max_inh_conductance)
#     print ("Done {}".format(index))
```

```python
fig, ax = plt.subplots()
cmap = matplotlib.cm.viridis

colors = matplotlib.cm.viridis(numpy.linspace(0, 1, len(all_inh_conductances)))

# norm = matplotlib.colors.Normalize(vmin=1, vmax=6)
slopeArr = []
for i, (g, gi, d, c) in enumerate(zip(all_conductances, all_inh_conductances, all_delays, colors)):
    g, gi, d = numpy.array(g), numpy.array(gi), numpy.array(d)
    indices = numpy.argsort(g)
    slope, intercept, rval, pvalue, err = ss.linregress(g[indices], gi[indices])
    #cbar = ax.scatter(g,d, c= [slope]*len(g), s= 10, cmap='viridis', vmin=1.5, vmax=3.2)
    slope, intercept, lowConf, upperConf = ss.mstats.theilslopes(x=gi[indices], y=d[indices])
    #slope, intercept, rval, pvalue, err = ss.linregress(g[indices], d[indices])
    cbar = ax.scatter(gi,d, s=8, c=c, alpha=0.4, cmap='viridis')
    ax.plot(gi, slope*gi + intercept,c=c)
    slopeArr.append(slope)

flattened_g = numpy.array([g for sublist in all_conductances for g in sublist])
flattened_d = numpy.array([d for sublist in all_delays for d in sublist])

ax.set_xlabel("$g_e$  (nS)")
ax.set_ylabel("$\\delta_i$ (ms)")
# plt.colorbar(cbar)
ax.set_ylim(ymin=-5)
simpleaxis(ax)
fig.set_figwidth(4.5)
fig.set_figheight(4.5)
dump(fig,file('figures/fig6/6l_1.pkl','wb'))
plt.show()
```

```python
fig, ax = plt.subplots()
bins = numpy.linspace(-3,0.25,13)
print(bins)
ax.hist(slopeArr,bins=bins,color='k')
ax.vlines(x=0,ymin=0,ymax=7.,color='r')
simpleaxis(ax)
fig.set_figwidth(1.5)
fig.set_figheight(1.5)
plt.show()
```

### Fitting through all cells

```python
cmap = matplotlib.cm.viridis
colors = matplotlib.cm.viridis(numpy.linspace(0, 1, len(all_inh_conductances)))
fig, ax = plt.subplots()
# norm = matplotlib.colors.Normalize(vmin=1, vmax=6)
slopeArr = []
adist, bdist = [],[]
for i, (g, gi, d, c) in enumerate(zip(all_conductances, all_inh_conductances, all_delays, colors)):
    g, gi, d = numpy.array(g), numpy.array(gi), numpy.array(d)
    indices = numpy.where(d>0)
    g, gi, d = g[indices], gi[indices], d[indices]
    indices = numpy.argsort(g)
    delay_Model = lmfit.Model(delay_excitation)
    delay_pars = delay_Model.make_params()

    delay_result = delay_Model.fit(d, delay_pars, x=g)
    indices = numpy.argsort(g)
#     ax.scatter(g[indices], d[indices], s=30, facecolor='k', edgecolor='k')
    ax.scatter(g[indices], d[indices], s=5, facecolor=colors[i], edgecolor=colors[i])
    ax.plot(g[indices], delay_result.best_fit[indices], '--', color=colors[i], linewidth=1)
    print ("{:.2f} + {:.2f}g_e^{:.2f}".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
    adist.append(delay_result.params['a'].value)
    bdist.append(delay_result.params['b'].value)
    print(delay_result.fit_report())
#     ax.set_xlabel("$g_e$ (nS)")
#     ax.set_ylabel("$\\delta_i$ (ms)")
    # dump(fig,file('figures/fig6/6k.pkl','wb'))
# flattened_g = numpy.array([g for sublist in all_conductances for g in sublist])
# flattened_d = numpy.array([d for sublist in all_delays for d in sublist])
# delay_Model = lmfit.Model(delay_excitation)
# delay_pars = delay_Model.make_params()

# delay_result = delay_Model.fit(flattened_d, delay_pars, x=flattened_g)
# indices = numpy.argsort(flattened_g)
# #     ax.scatter(g[indices], d[indices], s=30, facecolor='k', edgecolor='k')
# ax.plot(flattened_g[indices], delay_result.best_fit[indices], '-',color='k')
# print ("{:.2f} * g_e^{:.2f}".format(delay_result.params['a'].value, delay_result.params['b'].value))#, delay_result.params['c'].value))
# print(delay_result.fit_report())
ax.set_xlabel("$g_e$ (nS)")
ax.set_ylabel("$\\delta_i$ (ms)")
fig.set_figwidth(4.5)
fig.set_figheight(4.5)
ax.set_xlim(0,4.5)
simpleaxis(ax)
plt.show()
# ax.set_xticks(range(4))
# ax.set_yticks(range(0,12,2))

# ax.set_ylim(-3,12.5)

# print ("{:.2f} + {:.2f}e^-{:.2f}E".format(delay_result.params['a'].value, delay_result.params['b'].value, delay_result.params['c'].value))
```

```python
fig, ax = plt.subplots(3,1)
ax[0].hist(adist)
ax[1].hist(bdist,bins=5)
plt.show()
print(numpy.mean(adist))
print(numpy.mean(bdist))
```

```python
slopeArr
```

```python
fig, ax = plt.subplots()
cmap = matplotlib.cm.viridis

colors = matplotlib.cm.viridis(numpy.linspace(0, 1, len(all_inh_conductances)))

# norm = matplotlib.colors.Normalize(vmin=1, vmax=6)
for i, (g, gi, d, c) in enumerate(zip(all_conductances, all_inh_conductances, all_delays, colors)):
    g, gi, d = numpy.array(g), numpy.array(gi), numpy.array(d)
    indices = numpy.argsort(g)

#     slope, intercept, rval, pvalue, err = ss.linregress(g[indices], gi[indices])
#     print(slope)
    #cbar = ax.scatter(g,d, c= [slope]*len(g), s= 10, cmap='viridis', vmin=1.5, vmax=3.2)
#     print(g)
    gmax = numpy.ceil(max(g))
    gmin = numpy.floor(min(g))
    print(gmin, min(g), gmax, max(g))
#     bins = numpy.linspace(gmin,gmax,(gmax - gmin) +1)
    print (gmin, gmax)
    bins = numpy.arange(gmin,gmax,1)
    indices = numpy.argsort(g)

    digitized = numpy.digitize(g[indices], bins)
#     bins = range(8)
    g_means = numpy.array([g[indices][digitized == i].mean() for i in bins])
    g_err = numpy.array([g[indices][digitized == i].std() for i in bins])
    d_means = numpy.array([d[indices][digitized == i].mean() for i in bins])
    d_err = numpy.array([d[indices][digitized == i].std() for i in bins])

    finiteYmask = numpy.isfinite(g_means)
    d_means = d_means[finiteYmask]
    g_means = g_means[finiteYmask]
    d_err = d_err[finiteYmask]
    g_err = g_err[finiteYmask]

    slope, intercept, rval, pvalue, err = ss.linregress(g_means, d_means)

    ax.errorbar(g_means, d_means, xerr = g_err, yerr = d_err, linestyle='')
    cbar = ax.scatter(g_means, d_means, s=10, c=c, alpha=0.5, cmap='viridis')
#     indices = numpy.argsort(g_means)
    print(g_means, d_means, intercept, slope)
    ax.plot(g_means, intercept + slope*g_means, c=c)
plt.show()
```

```python
delay_Model = lmfit.Model(delay_excitation)
delay_pars = delay_Model.make_params()

indices = numpy.argsort(flattened_g)
flattened_g = flattened_g[indices]
flattened_d_fit = delay_result.eval(x=flattened_g)

delay_result = delay_Model.fit(flattened_d, delay_pars, x=flattened_g)

fig, ax = plt.subplots()
ax.scatter(flattened_g, flattened_d, s=10, alpha=0.2,c='k')

print(delay_result.fit_report())
ax.plot(flattened_g, flattened_d_fit)
plt.show()
# slope, intercept, rval, pvalue, err = ss.linregress(flattened_g[indices], flattened_d[indices])
# x_axis = numpy.linspace(numpy.min(flattened_g), numpy.max(flattened_g), 100)
# y_axis = slope * x_axis + intercept

# ax.set_xlim(0,6)
# ax.set_ylim(-3,10)

# ax.plot(x_axis, y_axis, '--')
print ( delay_result.params['a'],delay_result.params['b'],delay_result.params['c'])
```

```python
keySet = set(inh_onsets).intersection(exc_onsets)
```

```python
for key in keySet:
    print (inh_onsets[key], exc_onsets[key])
```

Paper_Figures/Figure 6 (Conductance model), Figure 5B (Model derived inhibition)-Copy1.ipynb