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

place fields #126

Open
wants to merge 49 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
60f1c75
Initial code draft
Oct 28, 2020
9e9c7c3
place fields almost working
bendichter Oct 28, 2020
4ff6a58
Merge branch 'master' into place_field
bendichter Oct 29, 2020
b752882
interactive widget working
bendichter Oct 29, 2020
8d5f754
interactive widget working
bendichter Oct 29, 2020
50e284c
NaN out unexplored territory
bendichter Oct 29, 2020
03f617b
1D place code widget
Oct 29, 2020
09e0669
1D place code widget working
Oct 30, 2020
c346a60
nelpy package integrated into 1D rate map widget
Oct 31, 2020
2e92ed4
1D rate map speed threshold implementation
Nov 2, 2020
7b48dc0
1D rate map normalization and collapsed view feature addition
Nov 3, 2020
ece7795
- Added Numpy docstring for plot_tuning_curves1D fxn
Nov 3, 2020
07a7ae7
Removed nelpy dependency
Nov 4, 2020
7f8a790
Moved analysis code to analysis/placefields.py
Nov 4, 2020
6fd92c1
Merge branch 'master' into place_field
bendichter Nov 4, 2020
55611dd
Dynamically route rate maps to correspond to dimensionality of the data
Nov 4, 2020
d0ff81b
Merge branch 'place_field' of https://github.com/NeurodataWithoutBord…
Nov 4, 2020
4c414fa
Merge branch 'master' into place_field
bendichter Nov 4, 2020
8b3bbad
Merge branch 'master' into place_field
bendichter Nov 4, 2020
0ff0037
Add optional TimeSeries of velocity as input
Nov 4, 2020
81c40b2
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
2601b86
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
7290f00
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
33f3c70
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
0f77f2d
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
45ae3ec
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
c7b0208
Update nwbwidgets/placefield.py
MRScheid Nov 5, 2020
fdb0d5b
Corrected velocity as optional input
Nov 5, 2020
69bc054
Cleaned up code, fixed single unit input bug
Nov 6, 2020
866236a
Merge branch 'master' into place_field
bendichter Nov 11, 2020
6fbd006
Removed group and sort controller. Added multi-select.
Nov 18, 2020
9dab486
* lru_cache
bendichter Nov 18, 2020
52d1706
correct index and cache
bendichter Nov 21, 2020
84e87aa
style and caching some analyses
bendichter Nov 24, 2020
6bb219e
Place field modification for towers task.
Dec 9, 2020
85dc581
Merge remote-tracking branch 'origin/place_field' into place_field
Dec 9, 2020
43080e8
Place field modification for towers task.
Dec 9, 2020
c365f2b
Fixed the "TypeError: unhashable type: 'numpy.ndarray" issue that aro…
Dec 10, 2020
194f457
Remove group and sort controller import
Dec 10, 2020
2624add
Re-factor code
Dec 12, 2020
d6905bc
Allow for different pixel width in x and y dimension
Dec 16, 2020
04cca71
Changes to accomodate towers task place field
Dec 17, 2020
6c68ddf
Added bin number control
Jan 25, 2021
3b7863d
Merge branch 'master' into place_field
MRScheid Mar 9, 2021
6e3c1b1
Simple formatting
Mar 9, 2021
d259182
Merge branch 'place_field' of https://github.com/NeurodataWithoutBord…
Mar 9, 2021
c9fa416
Update imports
Mar 9, 2021
c4cc8f6
Merge branch 'master' into place_field
MRScheid May 14, 2021
87a2433
Removed old ignore files
MRScheid May 17, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 110 additions & 23 deletions nwbwidgets/placefield.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,41 @@
from scipy.ndimage.filters import gaussian_filter, maximum_filter

import matplotlib.pyplot as plt
import nelpy.plotting as nlp
MRScheid marked this conversation as resolved.
Show resolved Hide resolved

import pynwb
from ipywidgets import widgets, BoundedFloatText, Dropdown


from .utils.widgets import interactive_output
from .utils.units import get_spike_times
from .utils.timeseries import get_timeseries_in_units, get_timeseries_tt
from .base import vis2widget

import plotly.graph_objects as go


## To-do
# [] Create PlaceFieldWidget class
# [X] Refactor place field calculation code to deal with nwb data type
# [X] Incorporate place field fxns into class
# [X] Change all internal attributes references
# [X]Change all internal method references

# [X] Get pos
# [X] Get time
# [X] Get spikes
# [] Get trials / epochs
# [X] Create PlaceFieldWidget class
# [X] Refactor place field calculation code to deal with nwb data type
# [X] Incorporate place field fxns into class
# [X] Change all internal attributes references
# [X]Change all internal method references

# [X] Get pos
# [X] Get time
# [X] Get spikes
# [] Get trials / epochs

# [X] Submit draft PR

# [] 1D Place Field Widget
# [X] Incorporate nelpy package into widget
# [] Add foreign group and sort controller to pick unit groups and ranges?
# [] Normalized firing rate figure?
# [] Add collapsed unit vizualization?
# [] Scale bar?
# [] Sort place cell tuning curves by peak firing rate position?
# [] Color palette control?

# [] Submit draft PR

# [] Modify plotly_show_spatial_trace to plot 2D heatmap representing place fields or create new figure function?
# [] Dropdown that controls which unit

# [x] Work in buttons / dropdowns / sliders to modify following parameters in place field calculation:
Expand Down Expand Up @@ -395,9 +403,18 @@ def compute_linear_firing_rate(pos, pos_tt, spikes, gaussian_sd=0.0557,
class PlaceField_1D_Widget(widgets.HBox):

def __init__(self, spatial_series: pynwb.behavior.SpatialSeries, **kwargs):
# foreign_group_and_sort_controller: GroupAndSortController = None,
# group_by=None,

super().__init__()

# if foreign_group_and_sort_controller:
# self.gas = foreign_group_and_sort_controller
# else:
# self.gas = self.make_group_and_sort(group_by=group_by, control_order=False)

self.units = spatial_series.get_ancestor('NWBFile').units

self.pos_tt = get_timeseries_tt(spatial_series)

istart = 0
Expand All @@ -417,7 +434,7 @@ def __init__(self, spatial_series: pynwb.behavior.SpatialSeries, **kwargs):
self.controls = dict(
gaussian_sd=bft_gaussian,
spatial_bin_len=bft_spatial_bin_len,
index=dd_unit_select
# index=dd_unit_select
)

out_fig = interactive_output(self.do_1d_rate_map, self.controls)
Expand All @@ -426,25 +443,95 @@ def __init__(self, spatial_series: pynwb.behavior.SpatialSeries, **kwargs):
widgets.VBox([
bft_gaussian,
bft_spatial_bin_len,
dd_unit_select
# dd_unit_select
]),
vis2widget(out_fig)
]

def do_1d_rate_map(self, index=0, gaussian_sd=0.0557, spatial_bin_len=0.0168):
def do_1d_rate_map(self, gaussian_sd=0.0557, spatial_bin_len=0.0168):
tmin = min(self.pos_tt)
tmax = max(self.pos_tt)

spikes = get_spike_times(self.units, index, [tmin, tmax])
index = np.arange(len(self.units))

spikes = get_spike_times(self.units, index[0], [tmin, tmax])
xx, occupancy, filtered_firing_rate = compute_linear_firing_rate(
self.pos, self.pos_tt, spikes, gaussian_sd=gaussian_sd, spatial_bin_len=spatial_bin_len)

fig, ax = plt.subplots()
all_unit_firing_rate = np.zeros([len(self.units), len(xx)])
all_unit_firing_rate[0] = filtered_firing_rate

fig = ax.plot(xx, filtered_firing_rate, '-')
ax.set_xlabel('x ({})'.format(self.unit))
ax.set_ylabel('firing rate (Hz)')
for ind in index[1:]:
spikes = get_spike_times(self.units, ind, [tmin, tmax])
_, _, all_unit_firing_rate[ind] = compute_linear_firing_rate(
self.pos, self.pos_tt, spikes, gaussian_sd=gaussian_sd, spatial_bin_len=spatial_bin_len)

# npl.set_palette(npl.colors.rainbow)
# with npl.FigureManager(show=True, figsize=(8, 8)) as (fig, ax):
# npl.utils.skip_if_no_output(fig)
fig, ax = plt.subplots()
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
fig, ax = plt.subplots()
fig, ax = plt.subplots(figsize=(7,7))

plot_tuning_curves1D(all_unit_firing_rate, xx, ax=ax, unit_labels=index)

# fig = ax.plot(xx, filtered_firing_rate, '-')
# ax.set_xlabel('x ({})'.format(self.unit))
# ax.set_ylabel('firing rate (Hz)')

return fig

def plot_tuning_curves1D(ratemap, bin_pos, ax=None, normalize=False, pad=10, unit_labels=None, fill=True, color=None):
"""
WARNING! This function is not complete, and hence 'private',
and may be moved somewhere else later on.
MRScheid marked this conversation as resolved.
Show resolved Hide resolved

If pad=0 then the y-axis is assumed to be firing rate
"""
xmin = bin_pos[0]
xmax = bin_pos[-1]
xvals = bin_pos

n_units, n_ext = ratemap.shape

# if normalize:
# peak_firing_rates = ratemap.max(axis=1)
# ratemap = (ratemap.T / peak_firing_rates).T

# determine max firing rate
max_firing_rate = ratemap.max()

if xvals is None:
xvals = np.arange(n_ext)
if xmin is None:
xmin = xvals[0]
if xmax is None:
xmax = xvals[-1]

for unit, curve in enumerate(ratemap):
if color is None:
line = ax.plot(xvals, unit*pad + curve, zorder=int(10+2*n_units-2*unit))
else:
line = ax.plot(xvals, unit*pad + curve, zorder=int(10+2*n_units-2*unit), color=color)
if fill:
# Get the color from the current curve
fillcolor = line[0].get_color()
ax.fill_between(xvals, unit*pad, unit*pad + curve, alpha=0.3, color=fillcolor, zorder=int(10+2*n_units-2*unit-1))

ax.set_xlim(xmin, xmax)
if pad != 0:
yticks = np.arange(n_units)*pad + 0.5*pad
ax.set_yticks(yticks)
ax.set_yticklabels(unit_labels)
ax.set_xlabel('external variable')
ax.set_ylabel('unit')
nlp.utils.no_yticks(ax)
nlp.utils.clear_left(ax)
else:
if normalize:
ax.set_ylabel('normalized firing rate')
else:
ax.set_ylabel('firing rate [Hz]')
ax.set_ylim(0)

nlp.utils.clear_top(ax)
nlp.utils.clear_right(ax)

return ax