Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MRG] NetworkPlot class to enable interactive visualizations and animations #649

Merged
merged 30 commits into from
May 23, 2024

Conversation

ntolley
Copy link
Contributor

@ntolley ntolley commented May 22, 2023

Here's my first pass at creating a viz class that can be used to quickly render the full 3D network, as well as membrane potentials of individual sections. This is meant to be largely generic and flexible so that it can be co-opted for other purposes. I think the most interesting applications at the moment would be:

  • Quickly generating animations of HNN simulations
  • Embedding the 3D plot into the current ipywidgets GUI

The current strategy for the class is to do all of the heavy lifting at the initialization (namely creating the 3D object, and mapping the voltage recordings to the appropriate colors). For a quick demo, the code below can be run on my laptop on a single core in approximately 20 sec:

from hnn_core import jones_2009_model, simulate_dipole
from hnn_core.network_models import add_erp_drives_to_jones_model
from hnn_core.viz import NetworkPlot

net = jones_2009_model()
net.set_cell_positions(inplane_distance=300)
add_erp_drives_to_jones_model(net)
dpl = simulate_dipole(net, dt=0.5, tstop=170, record_vsec='all')

net_plot = NetworkPlot(net)

image

If you want to play around with visualizing the voltages, you can try the following code block:

from ipywidgets import interact, IntSlider

def update_plot(t_idx, elev, azim):
    net_plot.update_section_voltages(t_idx)
    net_plot.elev = elev
    net_plot.azim = azim
    return net_plot.fig

time_slider = IntSlider(min=0, max=len(net_plot.times), value=1, continuous_update=False)
elev_slider = IntSlider(min=-100,max=100, value=10, continuous_update=False)
azim_slider = IntSlider(min=-100,max=100, value=-100, continuous_update=False)

interact(update_plot, t_idx=time_slider, elev=elev_slider, azim=azim_slider)

image

@ntolley
Copy link
Contributor Author

ntolley commented May 22, 2023

@jasmainak @rythorpe perhaps it'd be a good idea to make this a separate file? If we can find a solution to updating the section colors very rapidly, we can even consider adding a "play" button inside the GUI (or on the HNN website!) like the example here: https://matplotlib.org/stable/gallery/animation/unchained.html

@chenghuzi you might have some good insight on how to make the current code more "reactive"

@@ -0,0 +1,37 @@
"""
================================
XX. Modifying local connectivity
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to be fixed :)

Comment on lines 34 to 35
elev_slider = IntSlider(min=-100, max=100, value=10, continuous_update=False)
azim_slider = IntSlider(min=-100, max=100, value=-100, continuous_update=False)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't ipympl a dependency of hnn-gui ? Do you still need this?

@codecov-commenter
Copy link

codecov-commenter commented May 22, 2023

Codecov Report

Attention: Patch coverage is 95.17544% with 11 lines in your changes are missing coverage. Please review.

Project coverage is 91.51%. Comparing base (819f4f4) to head (db60ec2).
Report is 1 commits behind head on master.

Current head db60ec2 differs from pull request most recent head e9a94ef

Please upload reports for the commit e9a94ef to get more accurate results.

Files Patch % Lines
hnn_core/viz.py 95.13% 11 Missing ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #649      +/-   ##
==========================================
- Coverage   92.33%   91.51%   -0.82%     
==========================================
  Files          27       25       -2     
  Lines        5059     4819     -240     
==========================================
- Hits         4671     4410     -261     
- Misses        388      409      +21     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@jasmainak
Copy link
Collaborator

Agnostic about saving to a different file ... see my comment about the azimuth/elevation control. Maybe it makes the class thinner?

hnn_core/viz.py Outdated
@@ -1185,3 +1198,234 @@ def plot_laminar_csd(times, data, contact_labels, ax=None, colorbar=True,
plt_show(show)

return ax.get_figure()


class NetworkPlot:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class NetworkPlot:
class NetworkDataPlotter:

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NetworkPlotter? It might useful too for just visualizing the 3D morphology without any data too

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah if data is None

hnn_core/viz.py Outdated
self.init_network_plot()
self._update_axes()

def get_voltages(self):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if this should be in Network class ... then you can pass data to the NetworkDataPlotter class. You can plot not just voltages but other quantities

@ntolley
Copy link
Contributor Author

ntolley commented May 23, 2023

Dropping this here for easy testing once we get closer to merging. I think rendering movies is going to be a longish wait for larger networks, but not absurdly so (maybe like 5-10 minutes? if you downsample?)

import hnn_core
import os.path as op
from hnn_core import jones_2009_model, simulate_dipole, read_params
from hnn_core.network_models import add_erp_drives_to_jones_model
from hnn_core.viz import NetworkPlot

hnn_core_root = op.dirname(hnn_core.__file__)
params_fname = op.join(hnn_core_root, 'param', 'default.json')
params = read_params(params_fname)
params.update({'N_pyr_x': 3, 'N_pyr_y': 3})
net = jones_2009_model(params)
net.set_cell_positions(inplane_distance=300)
add_erp_drives_to_jones_model(net)
dpl = simulate_dipole(net, dt=0.5, tstop=170, record_vsec='all')

net_plot = NetworkPlot(net)
net_plot.export_movie('demo.gif', dpi=200)

demo

hnn_core/viz.py Outdated

self.ax.view_init(self._elev, self._azim)

def export_movie(self, fname, dpi=300):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jasmainak here's the export function!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some solutions here that might speed up the exporting by circumventing the matplotlib animation module:
https://stackoverflow.com/questions/4092927/generating-movie-from-python-without-saving-individual-frames-to-files

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to add a progressbar using a callback? I don't think the speed is a showstopper here. Maybe a param called "decim" could be added to take every nth frame. Make it work, make it nice, make it fast ...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely would be a nice addition but I think I'd need to be much more matplotlib savvy to know how to implement that 😄

@chenghuzi
Copy link
Collaborator

@jasmainak @rythorpe perhaps it'd be a good idea to make this a separate file? If we can find a solution to updating the section colors very rapidly, we can even consider adding a "play" button inside the GUI (or on the HNN website!) like the example here: https://matplotlib.org/stable/gallery/animation/unchained.html

@chenghuzi you might have some good insight on how to make the current code more "reactive"

Great work! Although, I'm concerned about the reactivity of our GUI. We are taking snapshots from the buffer and using imshow to render network images for now. So, it might be difficult to have real-time interaction in the new GUI with these new settings. But this will not affect the current function so there is nothing else to worry about.

hnn_core/viz.py Outdated Show resolved Hide resolved
###############################################################################
from hnn_core import jones_2009_model, simulate_dipole
from hnn_core.network_models import add_erp_drives_to_jones_model
from hnn_core.viz import NetworkPlot
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from hnn_core.viz import NetworkPlot
from hnn_core.viz import NetworkPlotter

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm guessing the name of this class got changed somewhere along the way and you forgot to update it here?

net_plot.azim = azim
return net_plot.fig

time_slider = IntSlider(min=0, max=len(net_plot.times), value=1, continuous_update=False)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason the interactive slider didn't work for me. It might be a version issue and totally unrelated to your code here. Have you encountered a similar issue at any point @ntolley?

@ntolley ntolley changed the title WIP: NetworkPlot class to enable interactive visualizations and animations [MRG] NetworkPlot class to enable interactive visualizations and animations Sep 25, 2023
@ntolley
Copy link
Contributor Author

ntolley commented Sep 25, 2023

@rythorpe @jasmainak this PR is ready for review! Two weird errors have come up however. First it seems like sphinx-gallery doesn't support python versions older than 3.8
image

Does this mean our minimum python version needs to be updated?

Also the windows unit tests are failing with an error in the GUI code...
image

This is the offending line in case you guys have any ideas on the possible cause:
https://github.com/ntolley/hnn-core/blob/e3aa27c91ba4ed7478d2214e53fea618b793f45b/hnn_core/tests/test_viz.py#L23C5-L23C5

@ntolley
Copy link
Contributor Author

ntolley commented Sep 25, 2023

@@ -27,7 +27,7 @@ jobs:
command: |
export PATH=~/miniconda/bin:$PATH
conda update --yes --quiet conda
conda create -n testenv --yes pip python=3.7
conda create -n testenv --yes pip python=3.8
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think we need to update setup.py and our unit tests with python>=3.8 as well to ensure all builds are getting tested properly?

Copy link
Contributor Author

@ntolley ntolley Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly if this only impacts the documentation building I don't think it's necessary

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's true but you won't realize if other dependencies start requiring 3.8 now that you have updated it here. I don't think we have a CI that tests for python < 3.8? Better to be consistent and update readme/setup etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and updated this in #677. We'll see if it fixes the Windows test_viz.py error....

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

excellent!!

@rythorpe
Copy link
Contributor

@rythorpe @jasmainak this PR is ready for review! Two weird errors have come up however. First it seems like sphinx-gallery doesn't support python versions older than 3.8 image

Does this mean our minimum python version needs to be updated?

Also the windows unit tests are failing with an error in the GUI code... image

This is the offending line in case you guys have any ideas on the possible cause: https://github.com/ntolley/hnn-core/blob/e3aa27c91ba4ed7478d2214e53fea618b793f45b/hnn_core/tests/test_viz.py#L23C5-L23C5

Ugh, I'm guessing the most recent version of matplotlib has diverged for windows vs. linux. Something to do with the agg backend....

@ntolley
Copy link
Contributor Author

ntolley commented Sep 25, 2023

Ok updating the python version used for CircleCI worked, however it seems something in the MNE code is breaking the somato example now:
image

hnn_core/viz.py Outdated Show resolved Hide resolved
doc/whats_new.rst Outdated Show resolved Hide resolved
@rythorpe
Copy link
Contributor

Aside from @jasmainak's spelling error and my incredibly nitpicky punctuation suggestion above, this looks great @ntolley !

hnn_core/viz.py Outdated Show resolved Hide resolved
@rythorpe rythorpe enabled auto-merge (rebase) May 23, 2024 18:11
@rythorpe
Copy link
Contributor

I've enabled auto-merge! Thanks @ntolley for this incredible feature - I'm very excited to put it to good use 😄

@rythorpe rythorpe merged commit 2aad36e into jonescompneurolab:master May 23, 2024
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants