__init__.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. import inspect
  2. import math
  3. from typing import Callable
  4. import numpy as np
  5. from view.python_core.ctvs.chunk_ctv_funcs_from_fidor import ctv_for_FIDOR_chunks_with_minmax_indices
  6. def ctv_dummy(
  7. time_trace, sampling_period,
  8. first_frame, last_frame,
  9. stimulus_number, stim_on_times, stim_off_times,
  10. flags, p1):
  11. """
  12. dummy CTV to specify function call signature
  13. :param time_trace: iterable of numbers
  14. :param sampling_period: float, sampling period of <time_trace>, in ms
  15. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  16. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  17. :param stimulus_number: int, indicates the which stimulus to use, use 1 for first stimulus
  18. :param stim_on_times: list of floats, stimulus onset times, in ms
  19. :param stim_off_times: list of floats, stimulus offset times, in ms
  20. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  21. :param p1: pandas.Series object, internal representation of data
  22. :rtype: list
  23. :return: one member, float
  24. """
  25. return [0]
  26. def ctv_0(
  27. time_trace, sampling_period,
  28. first_frame, last_frame,
  29. stimulus_number, stim_on_times, stim_off_times,
  30. flags, p1):
  31. """
  32. alias for ctv_303, retained for backward compatibility
  33. :param time_trace: iterable of numbers
  34. :param sampling_period: float, sampling period of <time_trace>, in ms
  35. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  36. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  37. :param stimulus_number: int, indicates the which stimulus to use, use 1 for first stimulus
  38. :param stim_on_times: list of floats, stimulus onset times, in ms
  39. :param stim_off_times: list of floats, stimulus offset times, in ms
  40. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  41. :param p1: pandas.Series object, internal representation of data
  42. :rtype: list
  43. :return: one member, float
  44. """
  45. return ctv_303(
  46. time_trace, sampling_period,
  47. first_frame, last_frame,
  48. stimulus_number, stim_on_times, stim_off_times,
  49. flags, p1
  50. )
  51. def ctv_22(
  52. time_trace, sampling_period,
  53. first_frame, last_frame,
  54. stimulus_number, stim_on_times, stim_off_times,
  55. flags, p1):
  56. """
  57. (mean of 3 frames around <last_frame>) – (mean of 3 frames around <first_frame>)
  58. :param time_trace: iterable of numbers
  59. :param sampling_period: float, sampling period of <time_trace>, in ms
  60. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  61. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  62. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  63. :param stim_on_times: list of floats, stimulus onset times, in ms
  64. :param stim_off_times: list of floats, stimulus offset times, in ms
  65. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  66. :param p1: pandas.Series object, internal representation of data
  67. :rtype: list
  68. :return: one member, float
  69. """
  70. first_frame_index = first_frame
  71. last_frame_index = last_frame
  72. assert 1 <= last_frame_index <= len(time_trace) - 2, f"Error calculating CTV 22: lastframe={last_frame} " \
  73. f"is invalid for data with {len(time_trace)} frames. " \
  74. f"Need three frames around lastframe."
  75. assert 1 <= first_frame_index <= len(time_trace) - 2, f"Error calculating CTV 22: firstframe={first_frame} " \
  76. f"is invalid for data with {len(time_trace)} frames. " \
  77. f"Need three frames around firstframe."
  78. ctv_value = np.mean(time_trace[last_frame_index - 1: last_frame_index + 2]) \
  79. - np.mean(time_trace[first_frame_index - 1: first_frame_index + 2])
  80. return [ctv_value]
  81. def ctv_222(
  82. time_trace, sampling_period,
  83. first_frame, last_frame,
  84. stimulus_number, stim_on_times, stim_off_times,
  85. flags, p1):
  86. """
  87. (mean of 4 frames starting at <last_frame>) – (mean of 4 frames starting at <first_frame>)
  88. :param time_trace: iterable of numbers
  89. :param sampling_period: float, sampling period of <time_trace>, in ms
  90. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  91. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  92. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  93. :param stim_on_times: list of floats, stimulus onset times, in ms
  94. :param stim_off_times: list of floats, stimulus offset times, in ms
  95. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  96. :param p1: pandas.Series object, internal representation of data
  97. :rtype: list
  98. :return: one member, float
  99. """
  100. first_frame_index = first_frame
  101. last_frame_index = last_frame
  102. assert 0 <= last_frame_index <= len(time_trace) - 4, f"Error calculating CTV 222: lastframe={last_frame} " \
  103. f"is invalid for data with {len(time_trace)} frames. " \
  104. f"Need three frames around lastframe."
  105. assert 0 <= first_frame_index <= len(time_trace) - 4, f"Error calculating CTV 22: firstframe={first_frame} " \
  106. f"is invalid for data with {len(time_trace)} frames. " \
  107. f"Need three frames around firstframe."
  108. ctv_value = np.mean(time_trace[last_frame_index: last_frame_index + 4]) - \
  109. np.mean(time_trace[first_frame_index: first_frame_index + 4])
  110. return [ctv_value]
  111. def ctv_35(
  112. time_trace, sampling_period,
  113. first_frame, last_frame,
  114. stimulus_number, stim_on_times, stim_off_times,
  115. flags, p1):
  116. """
  117. A - B where A=(three-frame-average around the maximum responses in an interval of 3 seconds after stimulus onset),
  118. B=(mean of 3 frames that preceed the onset of stimulus by LE_PrestimEndBackground frames)
  119. :param time_trace: iterable of numbers
  120. :param sampling_period: float, sampling period of <time_trace>, in ms
  121. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  122. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  123. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  124. :param stim_on_times: list of floats, stimulus onset times, in ms
  125. :param stim_off_times: list of floats, stimulus offset times, in ms
  126. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  127. :param p1: pandas.Series object, internal representation of data
  128. :rtype: list
  129. :return: one member, float
  130. """
  131. stim_on_frame_ind = int(stim_on_times[stimulus_number] / sampling_period) + 1
  132. frame_ind_after_3s_stim_onset = int((stim_on_times[stimulus_number] + 3000) / sampling_period) + 1
  133. # reset to end of trace if stimulus onset is less than 3 seconds before the end of trace
  134. frame_ind_after_3s_stim_onset = min(frame_ind_after_3s_stim_onset, len(time_trace) - 1)
  135. argmax_in_3s_after_stim_onset \
  136. = np.argmax(time_trace[stim_on_frame_ind: frame_ind_after_3s_stim_onset + 1]) + stim_on_frame_ind
  137. # make sure there are three frames around <argmax_in_3s_after_stim1_onset>. This will only happen if the
  138. # <argmax_in_3s_after_stim1_onset> happens to be the first or last frame
  139. argmax_in_3s_after_stim_onset = max(1, argmax_in_3s_after_stim_onset)
  140. argmax_in_3s_after_stim_onset = min(len(time_trace) - 2, argmax_in_3s_after_stim_onset)
  141. A = np.mean(time_trace[argmax_in_3s_after_stim_onset - 1: argmax_in_3s_after_stim_onset + 2])
  142. # make sure there are three frames around <stim1_on_frame_ind2use>. This will only happen if the
  143. # <stim1_on_frame_ind> happens to be the first or last frame
  144. stim_on_frame_ind2use = \
  145. min(max(1, stim_on_frame_ind - flags["LE_PrestimEndBackground"]), len(time_trace) - 2)
  146. B = np.mean(time_trace[stim_on_frame_ind2use - 1: stim_on_frame_ind2use + 2])
  147. return [A - B]
  148. def ctv_22and35(
  149. time_trace, sampling_period,
  150. first_frame, last_frame,
  151. stimulus_number, stim_on_times, stim_off_times,
  152. flags, p1):
  153. """
  154. feature 1: ctv_22; feature 2: ctv_35
  155. :param time_trace: iterable of numbers
  156. :param sampling_period: float, sampling period of <time_trace>, in ms
  157. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  158. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  159. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  160. :param stim_on_times: list of floats, stimulus onset times, in ms
  161. :param stim_off_times: list of floats, stimulus offset times, in ms
  162. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  163. :param p1: pandas.Series object, internal representation of data
  164. :rtype: list
  165. :return: two members, float
  166. """
  167. return [
  168. ctv_22(
  169. time_trace, sampling_period,
  170. first_frame, last_frame,
  171. stimulus_number, stim_on_times, stim_off_times,
  172. flags, p1)[0],
  173. ctv_35(
  174. time_trace, sampling_period,
  175. first_frame, last_frame,
  176. stimulus_number, stim_on_times, stim_off_times,
  177. flags, p1)[0]
  178. ]
  179. def ctv_300(
  180. time_trace, sampling_period,
  181. first_frame, last_frame,
  182. stimulus_number, stim_on_times, stim_off_times,
  183. flags, p1):
  184. """
  185. (definition taken forward from VIEW-IDL) mean of all frames, useful for simulated photographs
  186. :param time_trace: iterable of numbers
  187. :param sampling_period: float, sampling period of <time_trace>, in ms
  188. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  189. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  190. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  191. :param stim_on_times: list of floats, stimulus onset times, in ms
  192. :param stim_off_times: list of floats, stimulus offset times, in ms
  193. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  194. :param p1: pandas.Series object, internal representation of data
  195. :rtype: list
  196. :return: one member, float
  197. """
  198. return [np.nanmean(time_trace)]
  199. def ctv_301(
  200. time_trace, sampling_period,
  201. first_frame, last_frame,
  202. stimulus_number, stim_on_times, stim_off_times,
  203. flags, p1):
  204. """
  205. (definition taken forward from VIEW-IDL) mean of frames 5 to 10, which is generally before stimulus onset.
  206. Useful for morphological views.
  207. :param time_trace: iterable of numbers
  208. :param sampling_period: float, sampling period of <time_trace>, in ms
  209. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  210. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  211. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  212. :param stim_on_times: list of floats, stimulus onset times, in ms
  213. :param stim_off_times: list of floats, stimulus offset times, in ms
  214. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  215. :param p1: pandas.Series object, internal representation of data
  216. :rtype: list
  217. :return: one member, float
  218. """
  219. return [np.nanmean(time_trace[4: 10])]
  220. def ctv_302(
  221. time_trace, sampling_period,
  222. first_frame, last_frame,
  223. stimulus_number, stim_on_times, stim_off_times,
  224. flags, p1):
  225. """
  226. mean of frames from <first_frame> to <last_frame> (both inclusive).
  227. One possible use: calculate morphological image by specifying manually the range of frames to average.
  228. :param time_trace: iterable of numbers
  229. :param sampling_period: float, sampling period of <time_trace>, in ms
  230. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  231. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  232. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  233. :param stim_on_times: list of floats, stimulus onset times, in ms
  234. :param stim_off_times: list of floats, stimulus offset times, in ms
  235. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  236. :param p1: pandas.Series object, internal representation of data
  237. :rtype: list
  238. :return: one member, float
  239. """
  240. first_frame_index = first_frame
  241. last_frame_index = last_frame + 1
  242. assert 0 <= last_frame_index <= len(time_trace) - 1, f"Error calculating CTV 302: lastframe={last_frame} " \
  243. f"is invalid for data with {len(time_trace)} frames. "
  244. assert 0 <= first_frame_index <= len(time_trace) - 1, f"Error calculating CTV 302: firstframe={first_frame} " \
  245. f"is invalid for data with {len(time_trace)} frames. "
  246. return [np.nanmean(time_trace[first_frame_index: last_frame_index + 1])]
  247. def ctv_303(
  248. time_trace, sampling_period,
  249. first_frame, last_frame,
  250. stimulus_number, stim_on_times, stim_off_times,
  251. flags, p1):
  252. """
  253. Average of background frames, calculated using stimulus onset and the flags LE_StartBackground and
  254. LE_PrestimEndBackground. Can be useful to visualize and compare baseline values of signals.
  255. :param time_trace: iterable of numbers
  256. :param sampling_period: float, sampling period of <time_trace>, in ms
  257. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  258. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  259. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  260. :param stim_on_times: list of floats, stimulus onset times, in ms
  261. :param stim_off_times: list of floats, stimulus offset times, in ms
  262. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  263. :param p1: pandas.Series object, internal representation of data
  264. :rtype: list
  265. :return: one member, float
  266. """
  267. return [np.nanmean(time_trace[
  268. p1.metadata.background_frames[0]: p1.metadata.background_frames[1] + 1])]
  269. def ctv_330(
  270. time_trace, sampling_period,
  271. first_frame, last_frame,
  272. stimulus_number, stim_on_times, stim_off_times,
  273. flags, p1):
  274. """
  275. median of all frames
  276. :param time_trace: iterable of numbers
  277. :param sampling_period: float, sampling period of <time_trace>, in ms
  278. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  279. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  280. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  281. :param stim_on_times: list of floats, stimulus onset times, in ms
  282. :param stim_off_times: list of floats, stimulus offset times, in ms
  283. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  284. :param p1: pandas.Series object, internal representation of data
  285. :rtype: list
  286. :return: one member, float
  287. """
  288. return [np.nanmedian(time_trace)]
  289. def ctv_331(
  290. time_trace, sampling_period,
  291. first_frame, last_frame,
  292. stimulus_number, stim_on_times, stim_off_times,
  293. flags, p1):
  294. """
  295. median of frames 5 to 10, which is generally before stimulus onset.
  296. Useful for morphological views.
  297. :param time_trace: iterable of numbers
  298. :param sampling_period: float, sampling period of <time_trace>, in ms
  299. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  300. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  301. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  302. :param stim_on_times: list of floats, stimulus onset times, in ms
  303. :param stim_off_times: list of floats, stimulus offset times, in ms
  304. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  305. :param p1: pandas.Series object, internal representation of data
  306. :rtype: list
  307. :return: one member, float
  308. """
  309. return [np.nanmedian(time_trace[4: 10])]
  310. def ctv_332(
  311. time_trace, sampling_period,
  312. first_frame, last_frame,
  313. stimulus_number, stim_on_times, stim_off_times,
  314. flags, p1):
  315. """
  316. median of frames from <first_frame> to <last_frame> (both inclusive).
  317. One possible use: calculate morphological image by specifying manually the range of frames to average.
  318. :param time_trace: iterable of numbers
  319. :param sampling_period: float, sampling period of <time_trace>, in ms
  320. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  321. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  322. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  323. :param stim_on_times: list of floats, stimulus onset times, in ms
  324. :param stim_off_times: list of floats, stimulus offset times, in ms
  325. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  326. :param p1: pandas.Series object, internal representation of data
  327. :rtype: list
  328. :return: one member, float
  329. """
  330. first_frame_index = first_frame
  331. last_frame_index = last_frame + 1
  332. assert 0 <= last_frame_index <= len(time_trace) - 1, f"Error calculating CTV 302: lastframe={last_frame} " \
  333. f"is invalid for data with {len(time_trace)} frames. "
  334. assert 0 <= first_frame_index <= len(time_trace) - 1, f"Error calculating CTV 302: firstframe={first_frame} " \
  335. f"is invalid for data with {len(time_trace)} frames. "
  336. return [np.nanmedian(time_trace[first_frame_index: last_frame_index + 1])]
  337. def ctv_333(
  338. time_trace, sampling_period,
  339. first_frame, last_frame,
  340. stimulus_number, stim_on_times, stim_off_times,
  341. flags, p1):
  342. """
  343. Median of background frames, calculated using stimulus onset and the flags LE_StartBackground and
  344. LE_PrestimEndBackground. Can be useful to visualize and compare baseline values of signals.
  345. :param time_trace: iterable of numbers
  346. :param sampling_period: float, sampling period of <time_trace>, in ms
  347. :param first_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  348. :param last_frame: int, interpreted as a frame number, where frames are numbered 0, 1, 2...
  349. :param stimulus_number: int, indicates the which stimulus to use, where stimuli are numbered 0, 1, 2...
  350. :param stim_on_times: list of floats, stimulus onset times, in ms
  351. :param stim_off_times: list of floats, stimulus offset times, in ms
  352. :param flags: FlagsManager object, is a mapping of flag names to flags values with additional functions
  353. :param p1: pandas.Series object, internal representation of data
  354. :rtype: list
  355. :return: one member, float
  356. """
  357. return [np.nanmedian(time_trace[
  358. p1.metadata.background_frames[0]: p1.metadata.background_frames[1] + 1])]
  359. def ctv_chunk_magnitude_basic(
  360. time_trace, sampling_period=None,
  361. first_frame=None, last_frame=None,
  362. stimulus_number=None, stim_on_times=None, stim_off_times=None,
  363. flags=None, p1=None):
  364. """
  365. :param time_trace: iterable of numbers
  366. :param sampling_period: not used
  367. :param first_frame: not used
  368. :param last_frame: not used
  369. :param stimulus_number: not used
  370. :param stim_on_times: not used
  371. :param stim_off_times: not used
  372. :param flags: not used
  373. :param p1: not used
  374. :rtype: list
  375. :return: estimated_magnitude, base_ind, peak_ind
  376. estimated_magnitude: float, estimate of signal magnitude, kind of peak - baseline
  377. base_ind: int, index corresponding to the value used as baseline
  378. peak_ind, int, index corresponding to the value used as peak
  379. """
  380. return ctv_for_FIDOR_chunks_with_minmax_indices(time_trace)
  381. def get_custom_ctv_method(file, function_name):
  382. with open(file, 'r') as fh:
  383. import scipy
  384. exec(compile(fh.read(), "<string>", "exec"), {"np": np, "scipy": scipy}, locals())
  385. ctv_method = locals()[function_name]
  386. assert callable(ctv_method), f"The function '{function_name}' in {file} is not a function."
  387. assert inspect.signature(ctv_method) == inspect.signature(ctv_dummy), \
  388. f"The function '{function_name}' in {file} has an incorrect signature to be a CTV method"
  389. return ctv_method
  390. def get_ctv_function(ctv_method, ctv_method_file):
  391. to_return = None
  392. possible_function_name = f"ctv_{ctv_method}"
  393. if possible_function_name in globals():
  394. possible_function = globals()[possible_function_name]
  395. if callable(possible_function):
  396. return possible_function
  397. if to_return is None and type(ctv_method) is str:
  398. return get_custom_ctv_method(ctv_method_file, ctv_method)
  399. raise NotImplementedError
  400. def get_all_available_ctvs():
  401. available_ctvs = []
  402. for object_name, object in globals().items():
  403. if isinstance(object, Callable) and object_name.startswith("ctv_"):
  404. # to catch values like ctv_dummy
  405. try:
  406. available_ctvs += [int(object_name[4:])]
  407. except ValueError as ve:
  408. pass
  409. return available_ctvs