voltage propagation in the whole cell

Using the graphical user interface to build and exercise models. Includes customizing the GUI by writing a little bit of hoc or Python
Post Reply
xiaosage
Posts: 16
Joined: Sat May 11, 2013 10:01 am

voltage propagation in the whole cell

Post by xiaosage »

Hello,

I have downloaded a NEURON code and want to add a few lines to visualize the voltage propagation from a synaptic input site to the rest part of the neruon as time evolves. So far I only found some functions such as "Shape/PlotShape", but I am not sure whether they work or not. Can anyone tell me how to do it? Thanks!
ted
Site Admin
Posts: 6365
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: voltage propagation in the whole cell

Post by ted »

xiaosage wrote:want to . . . visualize the voltage propagation from a synaptic input site to the rest part of the neruon as time evolves.
What kind of a visualization do you want? You could just plot the time course of v in different parts of the model vs. time in the same graph. Then you can compare the detailed time course of v at each of those locations.
xiaosage
Posts: 16
Joined: Sat May 11, 2013 10:01 am

Re: voltage propagation in the whole cell

Post by xiaosage »

Hi Ted,

Thanks for your reply! I actually want to see the voltage distribution in the whole cell, for example, as the movie shown below

http://cns.iaf.cnrs-gif.fr/files/dendritRE_short.mpg

Thanks!
ted
Site Admin
Posts: 6365
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: voltage propagation in the whole cell

Post by ted »

Here's how to to generate such a graph by writing hoc code; it's even easier to do this with the GUI's tools.

First you'll need an instance of the PlotShape class, configured as a "shape plot," that will update at every fadvance.

Code: Select all

// this assumes you have already loaded the standard run system
// e.g. by double clicking on nrngui.hoc or some other hoc file
// or by starting NEURON by executing nrngui
// or by including either load_file("nrngui.hoc") or load_file("stdrun.hoc")
// at the top of your program
objref ps
ps = new PlotShape()
fast_flush_list.append(ps)
ps.exec_menu("Shape Plot")
Then you'll need to use the standard run system's movierun() instead of run().

Code: Select all

load_file("movierun.hoc")
Finally, when you're ready to run a simulation, use

Code: Select all

movierun()
If you want to make it run more slowly, specify the frame interval by using a hoc assignment statement that gives the parameter movie_frame_dur_ a value larger than 0.01 (seconds).
pedrofelix
Posts: 1
Joined: Thu Nov 28, 2024 8:33 am

Re: voltage propagation in the whole cell

Post by pedrofelix »

Hi,
I would like to do something similar for my project, and then export the plot, so that after the simulation I could have it saved as a "video" or something of sorts.

I have tried several approaches, but none seem to work.
Can you give me a hand on how to go about exporting the plot of the voltages changing over time?
I have made several different scripts (some with help from GPT and making use of other topics in the forum) to try to go about this, which I will go through below.

Code: Select all

def plot_view(folder=os.getcwd(),tmin=1e5,tmax=1e5,cell=None):
    ps=h.PlotShape(True)
    ps.variable("v")
    #ps.scale(-80, 30)
    h.fast_flush_list.append(ps)
    ps.exec_menu("Shape Plot")
    ps.exec_menu("Show Diam")
    ps.exec_menu("View = plot")
    
    output_dir="frames"
    out=os.path.join(folder,output_dir)
    os.makedirs(out, exist_ok=True)  # Create directory if it doesn't exist

    def save_files():
        t=h.t
        if t>=tmin and t>=tmax:
            filename=f"frame_{t:.2f}.eps"
            file=os.path.join(out,filename)
            ps.printfile(file)

    callback=h.beforestep_callback(cell.soma(0.5))
    callback.set_callback(save_files)
        
    return ps, callback
This first one is based on the implementation you suggested here, and it works regarding visualization of the voltages changing over time, but then I can't get it to save anything. Is there a way for me to do it?

Code: Select all

def morphology_voltage_movie(cell, folder,cmap=cm.cool,tmin=1e5,tmax=1e5):

    fig = go.FigureWidget()
    fig.update_layout(
        title="Membrane Voltage Over Time",
        scene=dict(
            xaxis=dict(title="X"),
            yaxis=dict(title="Y"),
            zaxis=dict(title="Z"),
        )
    )

    # Extract the morphology
    x_coords, y_coords, z_coords, arcs, diams, initial_v = [], [], [], [], [], []
    for sec in cell.all:
        for i in range(sec.n3d()):
            x=sec.x3d(i)
            y=sec.y3d(i)
            z=sec.z3d(i)
            arc=sec.arc3d(i)
            diam=sec.diam3d(i)
            x_coords.append(x)
            y_coords.append(y)
            z_coords.append(z)
            arcs.append(arc)
            diams.append(diam)

    for sec in cell.all:
        for seg in sec:
            initial_v.append(seg.v)

    # Normalize for the colormap
    vmin, vmax = -100, 50  # Adjust based on expected voltage range
    norm = cm.colors.Normalize(vmin=vmin, vmax=vmax)
    colors = [f"rgb{tuple((np.array(cmap(norm(v)))[:3] * 255).astype(int))}" for v in initial_v]

    scatter=go.Scatter3d(
        x=x_coords,
        y=y_coords,
        z=z_coords,
        mode='markers',
        marker=dict(
            size=5,
            color=colors,
            showscale=True,
            colorbar=dict(title="Voltage (mV)"),
            colorscale="Viridis"
        ),
        text=[f"Voltage: {v:.2f} mV" for v in initial_v]
        )
    fig.add_trace(scatter)

    # for sec in cell.all:
    #     for seg in sec:
    #         # x_coords.append(h.x3d(sec.arc3d(seg.x)))
    #         # y_coords.append(h.y3d(sec.arc3d(seg.x)))
    #         # z_coords.append(h.z3d(sec.arc3d(seg.x)))

    #         x_coords.append(seg.x_xtra)
    #         y_coords.append(seg.y_xtra)
    #         z_coords.append(seg.z_xtra)

    #         v_values.append(seg.v)  # Initial voltage

    output_dir="frames"
    out=os.path.join(folder,output_dir)
    os.makedirs(out, exist_ok=True)  # Create directory if it doesn't exist
 
    def update_plot():
        """
        Callback to update the morphology plot with current voltage values.
        """
        # Update voltage values
        current_voltages = []
        for sec in cell.all:
            for seg in sec:
                current_voltages.append(seg.v)

        # Map voltage to colors
        colors = [f"rgb{tuple((np.array(cmap(norm(v)))[:3] * 255).astype(int))}" for v in current_voltages]
        scatter.marker.color = colors
        scatter.text = [f"Voltage: {v:.2f} mV" for v in current_voltages]
          # Save frame to file
        if tmin <= h.t <= tmax:
            filename=f"frame_{h.t:.2f}.png"
            out_file=os.path.join(out,filename)
            fig.write_image(out_file)

    # Register the callback with NEURON
    callback = h.beforestep_callback(cell.soma(0.5))
    callback.set_callback(update_plot)
    
    return fig, callback
This one makes use of the way to add a colorbar described in viewtopic.php?p=20058#p20058, and also the beforestep_py mod file described in viewtopic.php?t=3389. In this I was trying to avoid using a PlotShape directly, cause it wasn't working for me, but have had no success in getting it to actually plot or save something.

Code: Select all

def plot_voltage_shape(folder,cell,max_shift):
   # locations=load_geometry(folder)
    voltages=load_voltages(folder)
    ps = h.PlotShape(False)
    vmin=min(max_shift)
    vmax=max(max_shift)

    ps.show(0)
    ps.variable("v")  # Associate the PlotShape with the 'v' variable
    ps.scale(vmin, vmax)  # Set the color scale
    fig=ps.plot(plotly, cmap=cm.cool)
    
    # Create a custom colormap using Matplotlib (cool colormap)
    cmap = cm.cool
    
    # Collect values of the variable from all segments
    # Create a colormap function
    colormap = cm.ScalarMappable(cmap=cmap, norm=mcolors.Normalize(vmin=0, vmax=1)).to_rgba

    # Map the normalized values to a Plotly colorscale as strings
    plotly_colorscale = [[v, f'rgb{tuple(int(255 * c) for c in colormap(v)[:3])}'] for v in np.linspace(0, 1, cmap.N)]

    # Create a separate scatter plot for the colorbar
    colorbar_trace = go.Scatter(
    x=[0],
    y=[0],
    mode='markers',
    marker=dict(
        colorscale=plotly_colorscale,
        cmin=vmin,
        cmax=vmax,
        colorbar=dict(
            title="Max Shift",
            thickness=20  # Adjust the thickness of the colorbar
        ),
        showscale=True
    )
    )

    # Add the colorbar trace to the figure
    fig.add_trace(colorbar_trace)
    fig.update_xaxes(showticklabels=False, showgrid=False)
    fig.update_yaxes(showticklabels=False, showgrid=False)
    fig.update_layout(
    plot_bgcolor='rgba(0,0,0,0)'
    )
    fig.show()

    def saveplot():
            output_dir="frames"
            out=os.path.join(folder,output_dir)
            os.makedirs(out, exist_ok=True)  # Create directory if it doesn't exist
            file=os.path.join(out,f"pshape_t{t}.eps")
            ps.printfile(file)

    for i,t in enumerate(voltages["t"]):
        v_values=voltages.iloc[i,1:]
        index=0
        for sec in cell.all:
            for seg in sec:
                seg.v=v_values[index]
                index+=1    

        saveplot()
This last one makes use of the voltages for each time step that I saved in a csv file. It doesn't work in regards to saving the plot, but even if it did, I can't help but think it's an inefficient way to go about it. I know I have made some mistakes, so I was hoping to get some guidance on how to fix them and how to go about doing this... Apologies if my post is too confusing and if there is missing information.
ted
Site Admin
Posts: 6365
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: voltage propagation in the whole cell

Post by ted »

Well, you're on the right track, but this can be done without explicit, formal use of callbacks. And the resulting code could be easily understood by all, even those who are new to Python. Some of the following discussion is for the benefit of others who may read this thread but have less experience with Python and programming.

Think about what you are trying to produce: a series of images that show how the colors in a graph change over time. Imagine how this will be done, and then write an algorithm in pseudocode that describes the process. Example:

Code: Select all

initialize a model
grab and save a snapshot of a graph that shows a "false color plot" of how membrane potential varies over the model cell
repeat
  advance the simulation by some time interval (one dt, or multiple dts, it's up to you)
  grab and save another snapshot
until time is >= when you want to stop
Assembling all those snapshots into a movie is a task that can be done with third party software after exiting from NEURON.

So now you have an algorithm and know how to
initialize a model: h.finitialize()
advance a simulation by a time step: h.fadvance()
or, if you prefer,
advance a simulation by multiple time steps: h.continuerun(h.t + DT) where DT is a whole number multiple of h.dt

I'd just use a PlotShape to create the false color plot of v (or whatever) over all the branches of a model cell. If NEURON's built-in InterViews renderings are too crude, you could try something else e.g. plotly

Code: Select all

import plotly
. . .
ps = h.PlotShape(False)
ps.variable('v')
ps.plot(plotly, cmap=cm.cool).show()
What else do you need to know? The following, which are quite ordinary Python tasks (not NEURON-specific), and examples of how to do them are all over the web:
how to grab and save a snapshot of a graph (well, this could be done with NEURON's built-in functions)
how to make sure that each snapshot has a unique name (preferably of the form basenamesequencenumber.extension) (I'd number each frame 0,1,2... instead of incorporating the actual time into the file name; you know what dt was)
how to assemble the snapshots into a "movie"

And there's probably more than one command line utility that can assemble a set of sequentially numbered images into a movie.
Post Reply