def figure3d(title):
    """Explore 3D model response to a faster hs rate for figure 3D.

    :param title: Plot title (panel label)
    :return: None
    """
    # Compute a 10000ms simulation with i_app=0 at t=0 and then i_app=0.16 at t=2000
    pattern = {0 * ureg.ms: 0 * uA_PER_CM2, 2000 * ureg.ms: 0.16 * uA_PER_CM2}
    ic = [-65 * ureg.mV, 1, 1]

    # Create curried function with partial to hide the scale kwargs and solve
    partial_ode = partial(ode_3d, scale=2)
    sol, t, stimulus = pulse(
        model=partial_ode,
        parameter_name="i_app",
        temporal_pattern=pattern,
        t_max=10000,
        ic=ic,
    )

    # Plot voltage trace
    plt.plot(t, sol[:, 0], "k")
    plt.plot(t, 30 * stimulus - 80, "grey")

    # Plot properties
    set_properties(
        title,
        y_label="V (mV)",
        y_tick=[-60, -40, -20, 0, 20],
        y_limits=(-80, 20),
        x_label="Time (ms)",
        x_tick=[0, 5000, 10000],
        x_limits=(0, 10000),
    )
def figure2b(title, panel=0):
    """Plot nullclines for different model regimes in different panels for 2B.

    Model regimes are taken from before depolarization block and after

    :param title: Plot title (panel label)
    :param panel: Which plot to make, without current (panel=0) or without current (panel=1)
    :return: None
    """
    # Select appropriate current regime depending on panel
    i_app = [0 * uA_PER_CM2, 3.5 * uA_PER_CM2][panel]

    # Compute nullcline and set the stability
    s = panel == 1  # panel==1 means 2nd panel is stable
    nullcline_figure(v_range=[-90 * ureg.mV, 50 * ureg.mV],
                     i_app=i_app,
                     stability=s)

    # Plot Properties
    y_label = "h" if panel == 0 else ""
    y_ticklabel = None if panel == 0 else []
    set_properties(
        title,
        x_label="V (mV)",
        y_label=y_label,
        x_tick=[-50, 0, 50],
        y_tick=[0, 0.1, 0.2, 0.3, 0.4],
        x_limits=[-75, 50],
        y_limits=[0, 0.4],
        y_ticklabel=y_ticklabel,
    )
Exemple #3
0
def figure4b(title, panel=0):
    """Perform bifurcation analysis of 2D and 3D system for 4B1/2.

    :param title: Plot title (panel label)
    :param panel: Which plot to make, 2D (panel=0) or 3d (panel=1)
    :return: None
    """
    # Compute contunuation and plot bifurcation diagram depending on the panel
    if panel == 0:
        figure4b1_continuation()
        x_label = ""
        x_tick = [-6, 0, 6]
    else:
        figure4b2_continuation()
        x_label = r"I$_{app}$($\mu$A/cm$^2$)"
        x_tick = [-0.1, 0, 0.2, 0.1]

    set_properties(
        title,
        y_label="V(mV)",
        y_tick=[-80, 0, 30],
        x_label=x_label,
        x_tick=x_tick,
        x_limits=(min(x_tick), max(x_tick)),
    )
def figure3b(title, panel=0):
    """Plot nullclines for different model regimes in different panels for 3B.

    :param title: Plot title (panel label)
    :param panel: Which plot to make ix referes to the index if the below i_app_list and hs_list
    :return: None
    """
    # different panels (ix) use a different parameters: set the appropriate one
    i_app = ([0, 0.16, 0.16, 0.16] * uA_PER_CM2)[panel]
    hs = [0.6, 0.6, 0.2, 0.05][panel]

    s = panel == 3  # 4th panel only is stable
    nullcline_figure(
        v_range=[-90 * ureg.mV, 50 * ureg.mV], i_app=i_app, stability=s, hs=hs
    )

    y_label = "h" if panel == 0 else ""
    y_ticklabel = None if panel == 0 else []

    set_properties(
        title,
        y_label=y_label,
        x_tick=[-40, 40],
        y_tick=[0, 0.2, 0.4, 0.6, 0.8],
        x_limits=(-80, 50),
        y_limits=(0, 0.6),
        y_ticklabel=y_ticklabel,
        x_label="V (mV)",
    )
def figure2a(title):
    """Compute 2d model response to step current input for figure 2A.

    :param title: Plot title (panel label)
    :return: None
    """
    # Compute a 3000ms simulation with i_app=0 at t=0 and then i_app=3.5 at t=2000
    pattern = {0 * ureg.ms: 0 * uA_PER_CM2, 2000 * ureg.ms: 3.5 * uA_PER_CM2}
    end_time = 3000 * ureg.ms
    initial_condition = [-35 * ureg.mV, 1]

    # Solve ode_2d for a current pulse with above parameters
    solution, t, waveform = pulse(
        model=ode_2d,
        parameter_name="i_app",
        temporal_pattern=pattern,
        t_max=end_time,
        ic=initial_condition,
    )

    # since the model remains in depolarization block the last time step is sufficient
    v = solution[:, 0]
    block_potential = v[-1]

    plt.text(
        2500,
        block_potential + 10,
        "{0:.1f}".format(block_potential),
        horizontalalignment="center",
    )

    # Plot voltage trace
    plt.plot(t, v, "k")
    plt.plot(t, waveform - 70, "grey")

    # Add an inset for ringing between 2000ms and 2100ms
    inset_axes = plt.gca().inset_axes([0.75, 0.5, 0.2, 0.47])
    inset_axes.plot(t, v, "k")
    inset_axes.set_xlim([2000, 2100])
    inset_axes.set_ylim([-50, 45])
    inset_axes.set_xticks([])
    inset_axes.set_yticks([])
    plt.gca().indicate_inset_zoom(inset_axes)

    # Plot properties
    set_properties(
        title,
        y_label="V (mV)",
        y_tick=[-60, -30, 0, 30],
        x_tick=[0, 1500, 3000],
        x_limits=[0, 3000],
    )
Exemple #6
0
def figure4a(title, panel=0):
    """Plot nullclines for different model currents (ix).

    :param title: Plot title (panel label)
    :param panel: Which plot to make ix refers to the index if the below i_app_list and hs_list
    :return: None
    """
    # Select appropriate i_app and hs for the panel used
    i_app_list = ([[0, 3.5], [0.16, 0.16, 0.16]] * uA_PER_CM2)[panel]
    hs_list = [[1, 1], [0.6, 0.2, 0.05]][panel]

    # Stability for each curve on each panel
    stability = [[False, True], [False, False, True]]

    # Iterate over the different v nullclines from the different i_app and hs values
    for iy, (i_app, hs) in enumerate(zip(i_app_list, hs_list)):
        nullcline_figure(
            v_range=[-90 * ureg.mV, 50 * ureg.mV],
            i_app=i_app,
            stability=stability[panel][iy],
            hs=hs,
            color_h="g",
            color_v="r",
        )

    if panel == 0:
        set_properties(
            title,
            x_label="V (mV)",
            y_label="h",
            x_tick=[-40, 0],
            y_tick=[0, 0.05, 0.1, 0.15],
            x_limits=(-40, 5),
            y_limits=(0, 0.15),
        )
        plt.annotate("",
                     xy=(-15, 0.05),
                     xytext=(-20, 0.07),
                     arrowprops=dict(arrowstyle="->"))
    else:
        set_properties(
            title,
            x_label="V (mV)",
            x_tick=[-60, 20],
            y_tick=[0, 0.2, 0.4],
            x_limits=(-80, 20),
            y_limits=(0, 0.4),
        )
        plt.annotate("",
                     xy=(-25, 0.3),
                     xytext=(-20, 0.2),
                     arrowprops=dict(arrowstyle="->"))
def figure3a(title, ix=0):
    """Compute 3d model response into depolarization block for step current input for figure 3A.

    :param title: Plot title (panel label)
    :param ix: Which figure to run: voltage (fig_num=0) or h (fig_num=1)
    :return: None
    """
    # Compute a 6000ms simulation with i_app=0 at t=0 and then i_app=0.16 at t=2000
    pattern = {0 * ureg.ms: 0 * uA_PER_CM2, 2000 * ureg.ms: 0.16 * uA_PER_CM2}
    ic = [-55 * ureg.mV, 0, 0]

    # Solve 3d model for above parameters and compute frequency
    solution, t_solved, stimulus = pulse(
        model=ode_3d,
        parameter_name="i_app",
        temporal_pattern=pattern,
        t_max=6000 * ureg.ms,
        ic=ic,
    )
    t_spike, f_spike = compute_instantaneous_frequency(solution[:, 0], t_solved)

    # Plot voltage data and add frequency axis for first panel
    if ix == 0:
        v = solution[:, 0]
        plot_secondary_frequency(t_spike, f_spike)
        plt.plot(t_solved, v, "k")
        plt.plot(t_solved, 10 * stimulus - 80, "grey")

        y_tick = [-60, -40, -20, 0, 20]

    else:
        h, hs = solution[:, 1], solution[:, 2]
        plt.plot(t_solved, h * hs, "k")
        plt.plot(t_solved, hs, "k--")
        plt.legend(["h$_{total}$", "h$_s$"], loc="upper right")

        y_tick = [0, 0.2, 0.4, 0.6, 0.8]

    xlabel = "" if ix == 0 else "Time (ms)"
    ylabel = "V (mV)" if ix == 0 else "h$_{total}$, h$_s$"
    x_ticklabel = [] if ix == 0 else None

    set_properties(
        title,
        y_label=ylabel,
        y_tick=y_tick,
        x_tick=[0, 3000, 6000],
        x_ticklabel=x_ticklabel,
        x_limits=[0, 6000],
        x_label=xlabel,
    )
def figure1d(title, panel=0, use_modified_tau_n=True):
    """Show waveforms for 5d (ix=0) or 3d (ix=1) models.

    :param title: Plot title (panel label)
    :param panel: Set the model to use 5d/3d (panel=0/1)
    :param use_modified_tau_n: Optional parameter to use the original tau_n which does not work. Defaults to our tau_n
    :return: None
    """
    # Select appropriate model depending on the panel
    model = [ode_5d, ode_3d][panel]

    # Run the simulation for 4200ms and start at an arbitrary point "close" to the limit cycle
    initial_condition = [-55 * ureg.mV, 0, 0]
    initial_condition = resize_initial_condition(initial_condition,
                                                 model,
                                                 fill=0)

    # Solve 5d model with appropriate tau_n
    if model == ode_5d:
        model = partial(ode_5d, use_modified_tau_n=use_modified_tau_n)

    t, sol = solve_ode(model,
                       initial_condition,
                       t_max=4200 * ureg.ms,
                       rtol=1e-3)

    # Throw away the first 1000ms of the simulation
    t_throw_away = np.where(t > 1000)[0][0]
    sol = sol[t_throw_away:, :]
    t = t[t_throw_away:] - t[t_throw_away]  # set new t[0]=0

    # Plot voltage trace
    plt.plot(t, sol[:, 0], "k")
    y_label = "V (mV)" if panel == 0 else ""
    y_tick_label = None if panel == 0 else []

    # Plot properties
    set_properties(
        title,
        x_label="Time (ms)",
        y_label=y_label,
        y_tick=[-80, -40, 0],
        y_limits=[-80, 20],
        y_ticklabel=y_tick_label,
        x_tick=[0, 1000, 2000, 3000],
        x_limits=[0, 3000],
    )
def figure_1a(title, g_na=5.92 * mS_PER_CM2 * 0.514, v_reset=-120 * ureg.mV):
    """Compute IV curve for 2d and 3d ode model.

    Based on the paper's reference of Seutin and Engel 2010 we believe what should have happened is Vm is clamped to
    -120 mV then Vm is clamped to a series of voltages: being returned to Vm=-120 each time. For each jump the peak Ina
    is computed

    Using the Paper's g_na = 5.92 we find a peak IV at -311 uA/cm^2 whereas the target is ~-160 uA/cm^2 so we rescale
    g_na to 5.92*160/311 which gives a peak IV curve at ~-160 uA/cm^2

    :param title: Plot title (panel label)
    :param g_na: Optional sodium conductance to use: defaults to working parameter
    :param v_reset: Optional reset potential: defaults to working parameter
    :return: None
    """
    # Compute an initial condition that is the model clamped at v_reset
    initial_condition = steady_state_when_clamped(v_reset)

    # Perform the same voltage clamp experiment for multiple models
    for model in [ode_3d, ode_2d]:
        initial_condition = resize_initial_condition(initial_condition, model)

        # Set plot properties for the model
        color, linestyle = ("grey", "solid") if model is ode_3d else ("black",
                                                                      "--")

        # compute IV curve
        current, voltage = current_voltage_curve(
            model=model,
            clamp_range=[-90 * ureg.mV, 60 * ureg.mV],
            t_max=500 * ureg.ms,
            ic=initial_condition,
            g_na=g_na,
        )
        # plot IV curve
        plt.plot(voltage, current, color=color, linestyle=linestyle)

    # plot settings
    plt.legend(["3D", "2D"], loc="center left", bbox_to_anchor=(0.4, 1.05))
    set_properties(
        title,
        x_label="V (mV)",
        y_label=r"I$_{Na}$($\mu$A/cm$^2$)",
        x_tick=[-80, -40, 0, 40],
        y_tick=[-160, 0],
    )
Exemple #10
0
def figure4c(title, panel=0):
    """Compute true IV curves for 2d and 3d model for figure 4C1/2.

    :param title: Plot title (panel label)
    :param panel: Which plot to make, 2D (label=0) or 3d (label=1)
    :return: None
    """
    # Select appropriate model given
    model = [ode_2d, ode_3d][panel]

    # Set IC
    ic = [-100 * ureg.mV, 1]
    ic = resize_initial_condition(ic, model, fill=1)

    # Compute IV curve
    current, voltage = current_voltage_curve(
        model=model,
        clamp_range=[-100 * ureg.mV, 20 * ureg.mV],
        t_max=3000 * ureg.ms,
        ic=ic,
        follow=True,
    )

    # plot IV curve
    plt.plot(voltage, current, "k")
    plt.plot(voltage, np.zeros(np.shape(voltage)), "--", color="grey")

    if panel == 0:
        set_properties(
            title,
            x_label="V (mV)",
            y_label=r"I$_{stim}$($\mu$A/cm$^2$)",
            x_tick=[-80, -40],
            y_tick=[-5, 0, 5],
            x_limits=(-100, -20),
            y_limits=(-5, 5),
        )
    else:
        set_properties(
            title,
            x_label="V (mV)",
            x_tick=[-70, -60, -50],
            y_tick=[-0.1, 0, 0.1, 0.2],
            x_limits=(-70, -50),
            y_limits=(-0.1, 0.2),
        )
def figure_1b(title, g_na=5.92 * mS_PER_CM2, pulse_width=5 * ureg.ms):
    """Compute the periodic step current response from figure 1B.

    Clamp to membrane potential to -80 then depolarize and rest the membrane potential to 0mV and -70mV every 100ms with
    5mV pulses to 0mV.

    In the original paper g_na is 9.12 mS/cm^2 and pulses are 5ms to reproduce their results we use g_na = 5.92 and a
    5 ms pulse

    :param title: Plot title (panel label)
    :param g_na:  Optional sodium conductance to use: defaults to working parameter
    :param pulse_width:  Optional pulse width (ms) to use: defaults to working parameter
    :return: None
    """
    # Create a 500ms simulation clamped at -80 which then goes through the 1b clamp pattern
    t_max = 500 * ureg.ms
    pattern = generate_clamp_pattern_1b(t_max, pulse_width=pulse_width)
    initial_condition = steady_state_when_clamped(v_clamp=-80 * ureg.mV)

    # Impose v_clamp according to pattern
    solution, time, waveform = pulse(
        model=ode_3d,
        parameter_name="v_clamp",
        temporal_pattern=pattern,
        t_max=t_max,
        ic=initial_condition,
        g_na=g_na,
    )

    # Compute sodium current and plot
    i_na = sodium_current(solution.T, default_parameters(g_na=g_na))

    # Plot Na function
    plt.plot(time, i_na, "k")

    # Plot properties
    set_properties(
        title,
        x_label="Time (ms)",
        y_label="",  # this is actually uA/cm^2
        x_tick=[0, 200, 400],
        y_tick=[-250, -200, 0],
        x_limits=[-50, 450],
    )
def figure_1c(title, use_modified_tau_n=True):
    """Compute limit cycle in n,h phase space for the 5d model and compute the approximation n=f(h) for 1C.

    :param title: Plot title (panel label)
    :param use_modified_tau_n: Optional parameter to use the original tau_n which does not work. Defaults to our tau_n
    :return: None
    """
    initial_condition = [
        -55 * ureg.mV,
        0,
        0,
        0,
        0,
    ]  # Does not need to lie on limit cycle since we throw away transient

    # Solve 5d model with appropriate tau_n
    partial_5d = partial(ode_5d, use_modified_tau_n=use_modified_tau_n)
    t, sol = solve_ode(partial_5d,
                       initial_condition,
                       t_max=4200 * ureg.ms,
                       rtol=1e-3)

    # Extract h and n and discard the first half due to transient
    ix_half_time = int(len(t) / 2)
    h = sol[ix_half_time:, 1]
    n = sol[ix_half_time:, 4]
    fit_f_approx(h, n)

    # Plot limit cycle in phase plane
    plt.plot(h, n, c="grey")
    plt.plot(h, f_approx(h), "k")

    # Plot properties
    plt.legend(["n", "n=f(h)"], loc="center left", bbox_to_anchor=(0.3, 1.05))
    set_properties(
        title,
        x_label="h",
        y_label="n",
        x_tick=[0, 0.2, 0.4, 0.6],
        y_tick=np.arange(0, 1, 0.2),
        x_limits=[0, 0.7],
    )
def figure3c(title):
    """Perform bifurcation analysis of 3D system for 3C.

    :param title: Plot title (panel label)
    :return: None
    """
    # Compute contunuation and plot bifurcation diagram
    figure3c_continuation()
    ic = [-60 * ureg.mV, 0, 1]

    # solve system and overlay hs,v trajectory - zorder plotting behind bifuraction diagram
    t, sol = solve_ode(model=ode_3d, ic=ic, t_max=10000, i_app=0.16)
    plt.plot(sol[:, 2], sol[:, 0], c="grey", zorder=-1e5, linewidth=0.5)

    set_properties(
        title,
        y_label="V (mV)",
        x_limits=[0, 1],
        x_tick=[0, 0.5, 1],
        y_tick=[-80, -40, 0, 40],
        x_label="hs",
    )
Exemple #14
0
def figure6(
    title,
    channel,
    version,
    ampa_scale=0.001,
    nmda_scale=3.7e-5,
    extract_time=7500 * ureg.ms,
):
    """Apply a synaptic pulse to the 3d model to determine potential at which depolarization block occurs.

    Original values in the paper do not seem to provide an accurate replication manual scaling was used
    (ampa and nmda_scale) to bring them into a working range

    :param title: Plot title (panel label)
    :param channel: Name of the channel nmda, ampa, i_app
    :param version: Version 0 or 1 of the parameters
    :param ampa_scale: Optional scale factor for ampa conductance
    :param nmda_scale: Optional scale factor for nmda conductance
    :param extract_time: Time where block voltage is computed (defaults to 7500ms)
    :return: None
    """
    # Containers for the function and parameter values for the different channels
    channel_types = {"nmda": nmda_current, "ampa": ampa_current, "i_app": None}
    all_parameters = {
        "nmda": [60 * nmda_scale, 60 * nmda_scale] * mS_PER_CM2,
        "ampa": [2.3 * ampa_scale, 7 * ampa_scale] * mS_PER_CM2,
        "i_app": [0.16, 0.32] * uA_PER_CM2,
    }

    # Initialize and set properties
    channel_function = channel_types[channel]
    on_value = all_parameters[channel][version]
    parameter_name = "i_app" if channel == "i_app" else "g_syn"
    pattern = {
        0 * ureg.ms: 0 * on_value.units,  # off at t=0
        2000 * ureg.ms: on_value,  # on at t=2000
        8000 * ureg.ms: 0 * on_value.units,  # off at t=8000
    }
    ic = [-65 * ureg.mV, 1, 1]

    # Create a curried ode_3d to take the synapse and solve it
    synapse_model = partial(ode_3d, synapse=channel_function)
    solution, t_solved, stimulus = pulse(
        model=synapse_model,
        parameter_name=parameter_name,
        temporal_pattern=pattern,
        t_max=10000 * ureg.mV,
        ic=ic,
    )

    # Plot voltage trace and extract block potential
    plt.plot(t_solved, solution[:, 0], "k")

    extract_ix = np.where(t_solved > strip_dimension(extract_time))[0][0]
    block_potential = solution[extract_ix, 0]
    plt.text(
        7500,
        block_potential + 10,
        "{0:.1f}".format(block_potential),
        horizontalalignment="center",
    )

    # Plot parameters
    y_ticklabel = None if version == 0 else []
    y_label = "V (mV)" if version == 0 else ""
    x_ticklabel = None if title[1] == "3" else []  # if row 3
    x_label = "Time (ms)" if title[1] == "3" else ""  # if row 3

    set_properties(
        title,
        y_label=y_label,
        y_tick=[-80, -40, 0],
        y_ticklabel=y_ticklabel,
        x_tick=[0, 5000, 10000],
        x_label=x_label,
        x_ticklabel=x_ticklabel,
    )