def test_step_subthreshold_interpolation(): target_amps = [-90, -70, -50, -30, -10] test_sweep_list = [] test_amps = [-70, -30] t = np.arange(6) i = np.zeros_like(t) epochs = { "sweep": (0, 5), "test": None, "recording": None, "experiment": None, "stim": None } sampling_rate = 1 clamp_mode = "CurrentClamp" for a in test_amps: v = np.hstack([np.zeros(2), np.ones(2) * a, np.zeros(2)]) test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) test_sweep_list.append(test_sweep) amp_sweep_dict = dict(zip(test_amps, test_sweep_list)) output = fv.step_subthreshold(amp_sweep_dict, target_amps, start=2, end=4, extend_duration=1, subsample_interval=1) assert np.all(output[1:3] == -90) assert np.array_equal(output[4:8], test_sweep_list[0].v[1:-1]) assert np.all(output[9:11] == -50) assert np.array_equal(output[12:16], test_sweep_list[1].v[1:-1]) assert np.all(output[17:19] == -10)
def test_divide_chirps_by_stimulus(): # Stuff for sweep construction sampling_rate = 2000 t = np.arange(0, 20 * sampling_rate) * (1 / sampling_rate) clamp_mode = "CurrentClamp" epochs = { "sweep": (0, len(t) - 1), "test": None, "recording": None, "experiment": None, "stim": None } i1 = scipy.signal.chirp(t, 0.5, 20, 40, method="linear") i2 = scipy.signal.chirp(t, 0.5, 20, 40, method="logarithmic") # linear descreasing profile profile = np.linspace(1., 0.5, num=len(t)) sweep_set = SweepSet([ Sweep(t, i * profile, i, clamp_mode, sampling_rate, epochs=epochs) for i in (i1, i2, i2) ]) divided_list = chirp.divide_chirps_by_stimulus(sweep_set) lengths = [len(d.sweeps) for d in divided_list] assert np.min(lengths) == 1 assert np.max(lengths) == 2 bigger_sweep_set = divided_list[np.argmax(lengths)] smaller_sweep_set = divided_list[np.argmin(lengths)] assert np.all(bigger_sweep_set.sweeps[0].i == bigger_sweep_set.sweeps[1].i) assert np.any( bigger_sweep_set.sweeps[0].i != smaller_sweep_set.sweeps[0].i)
def test_isi_shape_one_spike(): # Test sweep np.random.seed(42) v = np.zeros(1000) v[100:400] = np.linspace(-30, 0, 300) print(v[280:300]) t = np.arange(len(v)) i = np.zeros_like(t) epochs = {"sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None} sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) end = t[-100] test_threshold_index = [80] test_fast_trough_index = [100] test_threshold_v = [0] test_spike_info = pd.DataFrame({ "threshold_index": test_threshold_index, "fast_trough_index": test_fast_trough_index, "threshold_v": test_threshold_v, "fast_trough_t": test_fast_trough_index, }) n_points = 100 isi_norm = fv.isi_shape(test_sweep, test_spike_info, end, n_points=n_points, steady_state_interval=10, single_max_duration=500) assert len(isi_norm) == n_points assert isi_norm[0] < 0 assert isi_norm[0] >= -30
def test_identify_isi_shape_one_spike(): min_spike = 5 test_input_amplitudes = [10, 20, 30, 40] test_avg_rate = [0, 1, 1, 1] test_features = { "sweeps": pd.DataFrame({ "stim_amp": test_input_amplitudes, "avg_rate": test_avg_rate, }), "spikes_set": [None] * len(test_avg_rate), } # Random test sweeps np.random.seed(42) n_points = 100 t = np.arange(n_points) i = np.zeros_like(t) epochs = {"sweep": (0, n_points - 1), "test": None, "recording": None, "experiment": None, "stim": None} sampling_rate = 1 clamp_mode = "CurrentClamp" sweep_list = [] for a in test_input_amplitudes: v = np.random.randn(n_points) test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_list.append(test_sweep) test_sweep_set = SweepSet(sweep_list) selected_sweep, _ = fv.identify_sweep_for_isi_shape( test_sweep_set, test_features, duration=1, min_spike=min_spike) assert np.array_equal(selected_sweep.v, sweep_list[1].v)
def test_isi_shape_skip_short(): # Random test sweep np.random.seed(42) v = np.random.randn(1000) t = np.arange(len(v)) i = np.zeros_like(t) epochs = {"sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None} sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) end = t[-100] test_subsample = 3 test_threshold_index = np.array([100, 130, 150 + 100 * test_subsample]) test_fast_trough_index = test_threshold_index + 20 test_threshold_v = np.random.randint(-100, -20, size=len(test_threshold_index)) test_spike_info = pd.DataFrame({ "threshold_index": test_threshold_index, "fast_trough_index": test_fast_trough_index, "threshold_v": test_threshold_v, "fast_trough_t": test_fast_trough_index, }) n_points = 100 isi_norm = fv.isi_shape(test_sweep, test_spike_info, end, n_points=n_points) assert len(isi_norm) == n_points # Should only use second ISI assert isi_norm[0] == (test_sweep.v[test_fast_trough_index[1]:test_fast_trough_index[1] + test_subsample].mean() - test_threshold_v[1])
def test_first_ap_correct_section(): np.random.seed(42) v = np.random.randn(100) t = np.arange(len(v)) i = np.zeros_like(t) epochs = { "recording": (0, len(v) - 1), "test": None, "experiment": None, "stim": None, } sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) test_spike_index = 10 test_info = pd.DataFrame({"threshold_index": np.array([test_spike_index])}) window_length = 5 ap_v, ap_dv = fv.first_ap_vectors( [test_sweep], [test_info], target_sampling_rate=sampling_rate, window_length=window_length, ) assert np.array_equal( ap_v, test_sweep.v[test_spike_index:test_spike_index + window_length])
def test_subthresh_depol_norm_normalization(): np.random.seed(42) v = np.random.randn(100) t = np.arange(len(v)) i = np.zeros_like(t) epochs = { "sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None } sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) base = v[0] deflect_v = np.max(v) amp_sweep_dict = {10: test_sweep} deflect_dict = {10: (base, deflect_v)} output = fv.subthresh_depol_norm(amp_sweep_dict, deflect_dict, start=t[0], end=t[-1], steady_state_interval=1, subsample_interval=1, extend_duration=0) assert np.isclose(output[0], 0) assert np.isclose(output[-1], 1)
def test_chirp_downsample(): # Stuff for sweep construction sampling_rate = 2000 t = np.arange(0, 20 * sampling_rate) * (1 / sampling_rate) clamp_mode = "CurrentClamp" epochs = { "sweep": (0, len(t) - 1), "test": None, "recording": None, "experiment": None, "stim": None } base_chirp = scipy.signal.chirp(t, 0.5, 20, 40, method="linear") i = base_chirp # linear descreasing profile profile = np.linspace(1., 0.5, num=len(t)) v = base_chirp * profile test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_set = SweepSet([test_sweep]) amp, phase, freq = chirp.chirp_amp_phase(sweep_set, start=0, end=19.9, down_rate=sampling_rate / 2) # Confirm goes from 1 to 0.5 tol = 0.1 assert np.abs(amp[0] - 1) < tol assert np.abs(amp[-1] - 0.5) < tol
def test_first_ap_resampling(): np.random.seed(42) v = np.random.randn(100) t = np.arange(len(v)) i = np.zeros_like(t) epochs = { "sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None } sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) test_spike_index = 10 test_info = pd.DataFrame({"threshold_index": np.array([test_spike_index])}) window_length = 10 ap_v, ap_dv = fv.first_ap_vectors([test_sweep], [test_info], target_sampling_rate=sampling_rate / 2, window_length=window_length) assert ap_v.shape[0] == window_length / 2
def sweep_set_for_model(t, v, i): """Generate a SweepSet object based on a single model sweep Parameters ---------- t: array Time data (sec) v: array Voltage data (mV) i: array Current stimulus data (nA) Returns ------- SweepSet Contains one Sweep object """ sampling_rate = 1 / (t[1] - t[0]) sweep = Sweep(t=t, v=v, i=i, sampling_rate=sampling_rate, sweep_number=None, clamp_mode="CurrentClamp", epochs=None, ) return SweepSet([sweep])
def test_identify_sub_hyperpol_levels(): test_input_amplitudes = [-2000, -100, -90, -50, -10, 10] test_features = { "subthreshold_sweeps": pd.DataFrame( { "stim_amp": test_input_amplitudes, "peak_deflect": list( zip( np.zeros(len(test_input_amplitudes)), np.zeros(len(test_input_amplitudes)), ) ), "v_baseline": np.ones(len(test_input_amplitudes)), } ) } # Random test sweeps np.random.seed(42) v = np.random.randn(100) t = np.arange(len(v)) i = np.zeros_like(t) epochs = { "sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None, } sampling_rate = 1 clamp_mode = "CurrentClamp" sweep_list = [] for a in test_input_amplitudes: test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_list.append(test_sweep) test_sweep_set = SweepSet(sweep_list) amp_sweep_dict, deflect_dict = fv.identify_subthreshold_hyperpol_with_amplitudes( test_features, test_sweep_set ) for k in amp_sweep_dict: assert k in deflect_dict assert len(deflect_dict[k]) == 2 less_than_one_nanoamp = [a for a in test_input_amplitudes if a < -1000] for a in less_than_one_nanoamp: assert a not in amp_sweep_dict depolarizing = [a for a in test_input_amplitudes if a >= 0] for a in depolarizing: assert a not in amp_sweep_dict should_belong = [a for a in test_input_amplitudes if a >= 0 and a < -1000] for a in should_belong: assert a in amp_sweep_dict
def sweep(self, sweep_number): """ Create an instance of the Sweep class with the data loaded from the from a file Parameters ---------- sweep_number: int Returns ------- sweep: Sweep object """ sweep_data = self.get_sweep_data(sweep_number) sweep_record = self.get_sweep_record(sweep_number) sampling_rate = sweep_data['sampling_rate'] dt = 1. / sampling_rate t = np.arange(0, len(sweep_data['stimulus'])) * dt epochs = sweep_data.get('epochs') clamp_mode = sweep_record['clamp_mode'] if clamp_mode == "VoltageClamp": v = sweep_data['stimulus'] i = sweep_data['response'] elif clamp_mode == "CurrentClamp": v = sweep_data['response'] i = sweep_data['stimulus'] else: raise Exception("Unable to determine clamp mode for sweep " + sweep_number) v *= 1.0e3 # convert units V->mV i *= 1.0e12 # convert units A->pA if len(sweep_data['stimulus']) != len(sweep_data['response']): warnings.warn( "Stimulus duration {} is not equal reponse duration {}".format( len(sweep_data['stimulus']), len(sweep_data['response']))) try: sweep = Sweep( t=t, v=v, i=i, sampling_rate=sampling_rate, sweep_number=sweep_number, clamp_mode=clamp_mode, epochs=epochs, ) except Exception: logging.warning("Error reading sweep %d" % sweep_number) raise return sweep
def test_chirp_output(): # Stuff for sweep construction sampling_rate = 2000 t = np.arange(0, 20 * sampling_rate) * (1 / sampling_rate) clamp_mode = "CurrentClamp" epochs = { "sweep": (0, len(t) - 1), "test": None, "recording": None, "experiment": None, "stim": None } base_chirp = scipy.signal.chirp(t, 0.5, 20, 40, method="linear") i = base_chirp # linear descreasing profile profile = np.linspace(1., 0.5, num=len(t)) v = base_chirp * profile test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_set = SweepSet([test_sweep]) amp, phase, freq = chirp.chirp_amp_phase(sweep_set, start=0, end=19.9) # Confirm goes from 1 to 0.5 tol = 0.1 assert np.abs(amp[0] - 1) < tol assert np.abs(amp[-1] - 0.5) < tol # "resonant" profile profile = (-(t - 10)**2 + 100) / 100 + 1 v = base_chirp * profile test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_set = SweepSet([test_sweep]) amp, phase, freq = chirp.chirp_amp_phase(sweep_set, start=0, end=19.9) # Confirm it peaks around 2 near 20 Hz amp_tol = 0.1 freq_tol = 1 assert np.abs(np.max(amp) - 2) < amp_tol assert np.abs(freq[np.argmax(amp)] - 20) < freq_tol
def sweep(): i = [0, 0, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0] v = [0, 0, 1, 2, 1, 0, 0, 1, 2, 3, 1, 0, 0, 0, 0, 0] sampling_rate = 2 dt = 1. / sampling_rate t = np.arange(0, len(v)) * dt return Sweep(t, v, i, sampling_rate=sampling_rate, clamp_mode="CurrentClamp")
def test_step_subthreshold(): class Sweep: @property def v(self): return np.arange(10) @property def t(self): return np.arange(10) subthresh_hyperpol_dict = {-30.0: Sweep()} obtained = fv.step_subthreshold(subthresh_hyperpol_dict, [-30], 4, 6, subsample_interval=1) assert np.allclose(obtained, [4, 5])
def test_identify_sub_depol_levels_without_subthreshold_sweeps(): test_input_amplitudes = [-50, -10, 10, 20] test_avg_rate = [0, 0, 0, 5] test_features = {"sweeps": pd.DataFrame({ "stim_amp": test_input_amplitudes, "peak_deflect": list(zip(np.zeros(len(test_input_amplitudes)), np.zeros(len(test_input_amplitudes)))), "v_baseline": np.ones(len(test_input_amplitudes)), "avg_rate": test_avg_rate, })} # Random test sweeps np.random.seed(42) v = np.random.randn(100) t = np.arange(len(v)) i = np.zeros_like(t) epochs = {"sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None} sampling_rate = 1 clamp_mode = "CurrentClamp" sweep_list = [] for a in test_input_amplitudes: test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) sweep_list.append(test_sweep) test_sweep_set = SweepSet(sweep_list) amp_sweep_dict, deflect_dict = fv.identify_subthreshold_depol_with_amplitudes( test_features, test_sweep_set) for k in amp_sweep_dict: assert k in deflect_dict assert len(deflect_dict[k]) == 2 depolarizing_spiking = [a for a, r in zip(test_input_amplitudes, test_avg_rate) if a > 0 and r > 0] for a in depolarizing_spiking: assert a not in amp_sweep_dict depolarizing_non_spiking = [a for a, r in zip(test_input_amplitudes, test_avg_rate) if a > 0 and r == 0] for a in depolarizing_non_spiking: assert a in amp_sweep_dict hyperpolarizing = [a for a in test_input_amplitudes if a <= 0] for a in hyperpolarizing: assert a not in amp_sweep_dict
def sweeps_from_nwb(nwb_data, sweep_number_list): """ Generate a SweepSet object from an NWB reader and list of sweep numbers Sweeps should be in current-clamp mode. Parameters ---------- nwb_data: NwbReader sweep_number_list: list List of sweep numbers Returns ------- sweeps: SweepSet stim_start: float Start time of stimulus (seconds) stim_end: float End time of stimulus (seconds) """ sweep_list = [] start = None dur = None for sweep_number in sweep_number_list: sweep_data = nwb_data.get_sweep_data(sweep_number) sampling_rate = sweep_data["sampling_rate"] dt = 1.0 / sampling_rate t = np.arange(0, len(sweep_data["stimulus"])) * dt v = sweep_data["response"] * 1e3 # data from NWB now comes in Volts i = sweep_data["stimulus"] * 1e12 # data from NWB now comes in Amps sweep = Sweep( t=t, v=v, i=i, sampling_rate=sampling_rate, sweep_number=sweep_number, clamp_mode="CurrentClamp", epochs=None, ) sweep_list.append(sweep) start, dur, _, _, _ = stf.get_stim_characteristics(i, t) if start is None or dur is None: return SweepSet(sweep_list), None, None else: return SweepSet(sweep_list), start, start + dur
def sweep(self, sweep_number: int) -> Sweep: """ Create an instance of the Sweep class with the data loaded from the from a file Parameters ---------- sweep_number: int Returns ------- sweep: Sweep object """ sweep_data = self.get_sweep_data(sweep_number) sweep_metadata = self._data.get_sweep_metadata(sweep_number) time = np.arange(len( sweep_data["stimulus"])) / sweep_data["sampling_rate"] voltage, current = type(self)._voltage_current( sweep_data["stimulus"], sweep_data["response"], sweep_metadata["clamp_mode"], enforce_equal_length=True, ) try: sweep = Sweep( t=time, v=voltage, i=current, sampling_rate=sweep_data["sampling_rate"], sweep_number=sweep_number, clamp_mode=sweep_metadata["clamp_mode"], epochs=sweep_data.get("epochs", None), ) except Exception: logging.warning("Error reading sweep %d" % sweep_number) raise return sweep
def test_subthresh_depol_norm(): class Sweep: @property def v(self): return np.arange(10) @property def t(self): return np.arange(10) amp_sweep_dict = {50: Sweep()} deflect_dict = {50: (1, 2)} obtained = fv.subthresh_depol_norm( amp_sweep_dict, deflect_dict, 4, 7, subsample_interval=1, steady_state_interval=2 ) assert np.allclose([2/3, 8/9, 10/9], obtained)
def test_isi_shape_aligned(): # Random test sweep np.random.seed(42) v = np.random.randn(1000) t = np.arange(len(v)) i = np.zeros_like(t) epochs = { "sweep": (0, len(v) - 1), "test": None, "recording": None, "experiment": None, "stim": None, } sampling_rate = 1 clamp_mode = "CurrentClamp" test_sweep = Sweep(t, v, i, clamp_mode, sampling_rate, epochs=epochs) end = t[-100] test_threshold_index = np.array([100, 220, 340]) test_fast_trough_index = test_threshold_index + 20 test_threshold_v = np.random.randint( -100, -20, size=len(test_threshold_index) ) test_spike_info = pd.DataFrame( { "threshold_index": test_threshold_index, "fast_trough_index": test_fast_trough_index, "threshold_v": test_threshold_v, "fast_trough_t": test_fast_trough_index, } ) n_points = 100 isi_norm = fv.isi_shape( test_sweep, test_spike_info, end, n_points=n_points ) assert len(isi_norm) == n_points assert isi_norm[0] == np.mean( test_sweep.v[test_fast_trough_index[:-1]] - test_threshold_v[:-1] )
def test_isi_shape(): sweep_spike_info = { "fast_trough_index": [0, 10, -10000], "threshold_index": [-10000, 10, 20], "threshold_v": [1, 2, -10000], } class Sweep: @property def v(self): return np.arange(20) @property def t(self): return np.arange(20) obtained = fv.isi_shape(Sweep(), pd.DataFrame(sweep_spike_info), 50, n_points=10) assert np.allclose(np.arange(3.5, 13.5, 1.0), obtained)
def cell_id_to_sweep_set(abf_file_name, meta_info_df): curr_file = abf_file_name meta_dict = meta_info_df #curr_file = '15o08020.abf' meta_row = meta_dict.loc[meta_dict['cell_id'] == curr_file] file_path = meta_row['full_path'].values[0] stim_file_path = meta_row['stim_path'].values[0] resp_abf = pyabf.ABF(file_path) stim_abf = pyabf.ABF( stim_file_path ) # for some files we're using stim traces from a different file num_sweeps = int(meta_row['num_sweeps'].values[0]) stim_channel_num = int(meta_row['stim_chan'].values[0]) response_chan_num = int(meta_row['resp_chan'].values[0]) stim_gain = meta_row['stim_gain'].values[0] response_gain = meta_row['resp_gain'].values[0] start_time = meta_row['stim_start_time'].values[0] end_time = meta_row['stim_end_time'].values[0] resp_sampling_rate = meta_row['resp_sampling_rate'].values[0] stim_sampling_rate = meta_row['stim_sampling_rate'].values[0] resp_offset = meta_row['resp_offset'].values[0] stim_name = meta_row['stim_name'].values[0] stim_dict = get_stim_info(stim_abf, stim_channel_num, stim_gain, stim_name) stim_amps = stim_dict['stim_amp_vec'] # curr_epoch = (int(start_time*10000), int(end_time*10000)) # print(curr_epoch) clamp_mode = "CurrentClamp" sweep_list = list() for i in range(0, num_sweeps): sweep_num = i resp_abf.setSweep(sweep_num, channel=response_chan_num) time_vec = resp_abf.sweepX response_vec = resp_abf.sweepY * response_gain + resp_offset stim_abf.setSweep(sweep_num, channel=stim_channel_num) if stim_name == 'sweepY': stim_vec = stim_abf.sweepY * stim_gain else: stim_vec = stim_abf.sweepC * stim_gain # sometimes, when we get stim from a different file, they have diff samp rates 0_o if stim_sampling_rate != resp_sampling_rate: new_stim_vec = np.zeros(len(time_vec)) inds = np.where((time_vec > start_time) & (time_vec < end_time)) new_stim_vec[inds] = stim_amps[i] stim_vec = new_stim_vec #stim_vec = signal.resample(stim_vec, len(time_vec)) sweep = Sweep( t=time_vec, v=response_vec, i=stim_vec, sampling_rate=resp_sampling_rate, sweep_number=i, clamp_mode=clamp_mode, #epochs = curr_epoch ) sweep_list.append(sweep) sweep_set = SweepSet(sweep_list) return (sweep_set, start_time, end_time)