Skip to content

Commit

Permalink
Merge pull request #552 from AllenInstitute/release-1.0.7
Browse files Browse the repository at this point in the history
Release 1.0.7
  • Loading branch information
MatthewAitken authored Dec 6, 2022
2 parents 8c9d00d + 011bca8 commit 797e677
Show file tree
Hide file tree
Showing 10 changed files with 146 additions and 55 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@ All notable changes to this project will be documented in this file.

### Changed

## [1.0.7] = 2022-12-5
Changed:
- Added StimulusType and STIMULUS_TYPE_NAME_MAPPING to stimulus ontology, replacing definitions in EphysDataset
- Updated data_set_features to use correct sweep feature extractor detection parameters based on StimulusType

## [1.0.6] = 2022-6-29
Changed:
- Stop IPFX from caching its NWB Schemas when writing/modifying NWB files

## [1.0.5] = 2021-12-13
Bug fixes:
- Converts nwb_version attribute to string if it is in utf-8 encoded bytes.
Expand Down
46 changes: 30 additions & 16 deletions ipfx/data_set_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,28 @@
#
import functools
import numpy as np
from collections import defaultdict
import logging
from .feature_extractor import SpikeFeatureExtractor,SpikeTrainFeatureExtractor
from ipfx.dataset.ephys_data_set import EphysDataSet
from ipfx.stimulus import StimulusOntology, StimulusType, get_stimulus_type
from . import spike_features as spkf
from . import stimulus_protocol_analysis as spa
from . import stim_features as stf
from . import feature_record as fr
from . import error as er
from . import logging_utils as lu

DEFAULT_DETECTION_PARAMETERS = { 'dv_cutoff': 20.0, 'thresh_frac': 0.05 }

DETECTION_PARAMETERS = {
EphysDataSet.SHORT_SQUARE: {'thresh_frac_floor': 0.1 },
EphysDataSet.RAMP: { },
EphysDataSet.LONG_SQUARE: { }
}



DETECTION_PARAMETERS = defaultdict(
lambda: {},
{
# To override detection parameters for specific StimulusType, add it here.
# If not explicitly listed, default detection parameters will be used (see extractors_for_sweeps()).
# See ipfx.stimulus for stimulus types
StimulusType.SHORT_SQUARE: {'thresh_frac_floor': 0.1 },
StimulusType.CHIRP: {"filter_frequency": None}
}
)


SUBTHRESHOLD_LONG_SQUARE_MIN_AMPS = {
Expand All @@ -65,8 +67,18 @@
TEST_PULSE_DURATION_SEC = 0.4


def detection_parameters(stimulus_name):
return DETECTION_PARAMETERS.get(stimulus_name, {})
def detection_parameters(stimulus_type):
return DETECTION_PARAMETERS[stimulus_type]


def detection_parameters_from_stimulus_name(stimulus_name):
try:
stimulus_type = get_stimulus_type(stimulus_name)
dp = detection_parameters(stimulus_type)
except ValueError as e:
logging.warning(f"Warning: {e}\nUsing default detection parameters")
dp = detection_parameters(None)
return dp


def record_errors(fn):
Expand Down Expand Up @@ -102,6 +114,7 @@ def extractors_for_sweeps(sweep_set,
dv_cutoff=20., thresh_frac=0.05,
reject_at_stim_start_interval=0,
min_peak=-30,
filter_frequency=10.,
thresh_frac_floor=None,
est_window=None,
start=None, end=None):
Expand Down Expand Up @@ -139,6 +152,7 @@ def extractors_for_sweeps(sweep_set,
start=start,
end=end,
min_peak=min_peak,
filter=filter_frequency,
reject_at_stim_start_interval=reject_at_stim_start_interval)

stfx = SpikeTrainFeatureExtractor(start, end)
Expand All @@ -162,7 +176,7 @@ def extract_sweep_features(data_set, sweep_table):
sweep_set = data_set.sweep_set(sweep_numbers)
sweep_set.align_to_start_of_epoch("experiment")

dp = detection_parameters(stimulus_name).copy()
dp = detection_parameters_from_stimulus_name(stimulus_name).copy()
for k in [ "start", "end" ]:
if k in dp:
dp.pop(k)
Expand Down Expand Up @@ -246,7 +260,7 @@ def extract_cell_long_square_features(data_set, subthresh_min_amp=None):
lsq_spx, lsq_spfx = extractors_for_sweeps(lsq_sweeps,
start=lsq_start,
end=lsq_start+lsq_dur,
**detection_parameters(data_set.LONG_SQUARE))
**detection_parameters(StimulusType.LONG_SQUARE))

lsq_an = spa.LongSquareAnalysis(lsq_spx, lsq_spfx,
subthresh_min_amp=subthresh_min_amp)
Expand Down Expand Up @@ -285,7 +299,7 @@ def extract_cell_short_square_features(data_set):
SSQ_WINDOW = 0.001
ssq_spx, ssq_spfx = extractors_for_sweeps(ssq_sweeps,
est_window=[ssq_start, ssq_start+SSQ_WINDOW],
**detection_parameters(data_set.SHORT_SQUARE))
**detection_parameters(StimulusType.SHORT_SQUARE))

ssq_an = spa.ShortSquareAnalysis(ssq_spx, ssq_spfx)

Expand Down Expand Up @@ -315,7 +329,7 @@ def extract_cell_ramp_features(data_set):

ramp_spx, ramp_spfx = extractors_for_sweeps(ramp_sweeps,
start=ramp_start,
**detection_parameters(data_set.RAMP))
**detection_parameters(StimulusType.RAMP))
ramp_an = spa.RampAnalysis(ramp_spx, ramp_spfx)
ramp_features = ramp_an.analyze(ramp_sweeps)
return ramp_an.as_dict(
Expand Down
6 changes: 0 additions & 6 deletions ipfx/dataset/ephys_data_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ class EphysDataSet(object):
SWEEP_NUMBER,
]

LONG_SQUARE = 'long_square'
COARSE_LONG_SQUARE = 'coarse_long_square'
SHORT_SQUARE_TRIPLE = 'short_square_triple'
SHORT_SQUARE = 'short_square'
RAMP = 'ramp'

VOLTAGE_CLAMP = "VoltageClamp"
CURRENT_CLAMP = "CurrentClamp"

Expand Down
15 changes: 15 additions & 0 deletions ipfx/defaults/stimulus_ontology.json
Original file line number Diff line number Diff line change
Expand Up @@ -2043,5 +2043,20 @@
"core",
"Core 1"
]
],
[
[
"code",
"C2CHIRPA",
"C2CHIRPA180503"
],
[
"core",
"Core 2"
],
[
"name",
"Chirp A Threshold"
]
]
]
7 changes: 4 additions & 3 deletions ipfx/script_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import ipfx.data_set_features as dsf
import ipfx.time_series_utils as tsu
import ipfx.error as er
from ipfx.stimulus import StimulusType
from ipfx.sweep import SweepSet
from ipfx.dataset.create import create_ephys_data_set

Expand Down Expand Up @@ -221,7 +222,7 @@ def preprocess_long_square_sweeps(data_set, sweep_numbers, extra_dur=0.2, subthr
start=lsq_start,
end=lsq_end,
min_peak=-25,
**dsf.detection_parameters(data_set.LONG_SQUARE)
**dsf.detection_parameters(StimulusType.LONG_SQUARE)
)
lsq_an = spa.LongSquareAnalysis(lsq_spx, lsq_spfx,
subthresh_min_amp=subthresh_min_amp)
Expand All @@ -243,7 +244,7 @@ def preprocess_short_square_sweeps(data_set, sweep_numbers, extra_dur=0.2, spike
start=ssq_start,
end=ssq_end + spike_window,
reject_at_stim_start_interval=0.0002,
**dsf.detection_parameters(data_set.SHORT_SQUARE))
**dsf.detection_parameters(StimulusType.SHORT_SQUARE))
ssq_an = spa.ShortSquareAnalysis(ssq_spx, ssq_spfx)
ssq_features = ssq_an.analyze(ssq_sweeps)

Expand All @@ -259,7 +260,7 @@ def preprocess_ramp_sweeps(data_set, sweep_numbers):
ramp_start, ramp_dur, _, _, _ = stf.get_stim_characteristics(ramp_sweeps.sweeps[0].i, ramp_sweeps.sweeps[0].t)
ramp_spx, ramp_spfx = dsf.extractors_for_sweeps(ramp_sweeps,
start = ramp_start,
**dsf.detection_parameters(data_set.RAMP))
**dsf.detection_parameters(StimulusType.RAMP))
ramp_an = spa.RampAnalysis(ramp_spx, ramp_spfx)
ramp_features = ramp_an.analyze(ramp_sweeps)

Expand Down
104 changes: 81 additions & 23 deletions ipfx/stimulus.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,70 @@

import allensdk.core.json_utilities as ju

from enum import Enum


class StimulusType(Enum):
RAMP = "ramp"
LONG_SQUARE = "long_square"
COARSE_LONG_SQUARE = "coarse_long_square"
SHORT_SQUARE_TRIPLE = "short_square_triple"
SHORT_SQUARE = "short_square"
CHIRP = "chirp"
SEARCH = "search"
TEST = "test"
BLOWOUT = "blowout"
BATH = "bath"
SEAL = "seal"
BREAKIN = "breakin"
EXTP = "extp"


STIMULUS_TYPE_NAME_MAPPING = {
# Maps stimulus type to set of names
StimulusType.RAMP: {"Ramp"},
StimulusType.LONG_SQUARE: {
"Long Square",
"Long Square Threshold",
"Long Square SupraThreshold",
"Long Square SubThreshold",
},
StimulusType.COARSE_LONG_SQUARE: {
"C1LSCOARSE",
},
StimulusType.SHORT_SQUARE_TRIPLE: {
"Short Square - Triple",
},
StimulusType.SHORT_SQUARE: {
"Short Square",
"Short Square Threshold",
"Short Square - Hold -60mV",
"Short Square - Hold -70mV",
"Short Square - Hold -80mV",
},
StimulusType.CHIRP: {
"Chirp",
"Chirp A Threshold",
"Chirp B - Hold -65mV",
"Chirp C - Hold -60mV",
"Chirp D - Hold -55mV",
},
StimulusType.SEARCH: {"Search"},
StimulusType.TEST: {"Test"},
StimulusType.BLOWOUT: {"EXTPBLWOUT"},
StimulusType.BATH: {"EXTPINBATH"},
StimulusType.SEAL: {"EXTPCllATT"},
StimulusType.BREAKIN: {"EXTPBREAKN"},
StimulusType.EXTP: {"EXTP"}
}


def get_stimulus_type(stimulus_name):
for stim_type, stim_names in STIMULUS_TYPE_NAME_MAPPING.items():
if stimulus_name in stim_names:
return stim_type
else:
raise ValueError(f"stimulus_name {stimulus_name} not found.\nSTIMULUS_TYPE_NAME_MAPPING: {STIMULUS_TYPE_NAME_MAPPING}")


class Stimulus(object):
Expand Down Expand Up @@ -45,29 +109,23 @@ def __init__(self, stim_ontology_tags=None):

self.stimuli = list(Stimulus(s) for s in stim_ontology_tags)

self.ramp_names = ( "Ramp",)

self.long_square_names = ( "Long Square",
"Long Square Threshold",
"Long Square SupraThreshold",
"Long Square SubThreshold" )

self.coarse_long_square_names = ( "C1LSCOARSE",)
self.short_square_triple_names = ( "Short Square - Triple", )

self.short_square_names = ( "Short Square",
"Short Square Threshold",
"Short Square - Hold -60mV",
"Short Square - Hold -70mV",
"Short Square - Hold -80mV" )

self.search_names = ("Search",)
self.test_names = ("Test",)
self.blowout_names = ( 'EXTPBLWOUT', )
self.bath_names = ( 'EXTPINBATH', )
self.seal_names = ( 'EXTPCllATT', )
self.breakin_names = ( 'EXTPBREAKN', )
self.extp_names = ( 'EXTP', )
# Must match Stimulus Type Name Mapping, e.g
# for stimulus_type, names in _STIMULUS_TYPE_NAME_MAPPING.items():
# setattr(self, f"{stimulus_type.upper()}_NAMES", names)
self.ramp_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.RAMP]
self.long_square_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.LONG_SQUARE]
self.coarse_long_square_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.COARSE_LONG_SQUARE]
self.short_square_triple_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.SHORT_SQUARE_TRIPLE]
self.short_square_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.SHORT_SQUARE]
self.chirp_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.CHIRP]
self.search_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.SEARCH]
self.test_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.TEST]
self.blowout_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.BLOWOUT]
self.bath_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.BATH]
self.seal_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.SEAL]
self.breakin_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.BREAKIN]
self.extp_names = STIMULUS_TYPE_NAME_MAPPING[StimulusType.EXTP]


def find(self, tag, tag_type=None):
"""
Expand Down
2 changes: 1 addition & 1 deletion ipfx/version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.6
1.0.7
Git LFS file not shown
Git LFS file not shown
Git LFS file not shown

0 comments on commit 797e677

Please sign in to comment.