diff --git a/doc/api.rst b/doc/api.rst index 1ac37e4740..afc3e38ab2 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -159,6 +159,8 @@ spikeinterface.preprocessing .. autofunction:: common_reference .. autofunction:: correct_lsb .. autofunction:: correct_motion + .. autofunction:: get_motion_presets + .. autofunction:: get_motion_parameters_preset .. autofunction:: depth_order .. autofunction:: detect_bad_channels .. autofunction:: directional_derivative @@ -324,15 +326,21 @@ spikeinterface.curation ------------------------ .. automodule:: spikeinterface.curation - .. autoclass:: CurationSorting - .. autoclass:: MergeUnitsSorting - .. autoclass:: SplitUnitSorting + .. autofunction:: apply_curation .. autofunction:: get_potential_auto_merge .. autofunction:: find_redundant_units .. autofunction:: remove_redundant_units .. autofunction:: remove_duplicated_spikes .. autofunction:: remove_excess_spikes + +Deprecated +~~~~~~~~~~ +.. automodule:: spikeinterface.curation + .. autofunction:: apply_sortingview_curation + .. autoclass:: CurationSorting + .. autoclass:: MergeUnitsSorting + .. autoclass:: SplitUnitSorting spikeinterface.generation diff --git a/doc/how_to/handle_drift.rst b/doc/how_to/handle_drift.rst index fae4e8d2f6..eb19665874 100644 --- a/doc/how_to/handle_drift.rst +++ b/doc/how_to/handle_drift.rst @@ -1,4 +1,4 @@ -.. code:: ipython +.. code:: ipython3 %matplotlib inline %load_ext autoreload @@ -7,12 +7,12 @@ Handle motion/drift with spikeinterface ======================================= -SpikeInterface offers a very flexible framework to handle drift as a +Spikeinterface offers a very flexible framework to handle drift as a preprocessing step. If you want to know more, please read the -:ref:`motion_correction` section of the documentation. +``motion_correction`` section of the documentation. Here is a short demo on how to handle drift using the high-level -function :py:func:`~spikeinterface.preprocessing.correct_motion()`. +function ``spikeinterface.preprocessing.correct_motion()``. This function takes a preprocessed recording as input and then internally runs several steps (it can be slow!) and returns a lazy @@ -34,7 +34,7 @@ parameters. The high-level function suggests 3 predifined “presets” and we will explore them using a very well known public dataset recorded by Nick Steinmetz: `Imposed motion -datasets `_ +datasets `__ This dataset contains 3 recordings and each recording contains a Neuropixels 1 and a Neuropixels 2 probe. @@ -42,7 +42,7 @@ Neuropixels 1 and a Neuropixels 2 probe. Here we will use *dataset1* with *neuropixel1*. This dataset is the *“hello world”* for drift correction in the spike sorting community! -.. code:: ipython +.. code:: ipython3 from pathlib import Path import matplotlib.pyplot as plt @@ -52,12 +52,15 @@ Here we will use *dataset1* with *neuropixel1*. This dataset is the import spikeinterface.full as si -.. code:: ipython + from spikeinterface.preprocessing import get_motion_parameters_preset, get_motion_presets - base_folder = Path('/mnt/data/sam/DataSpikeSorting/imposed_motion_nick') - dataset_folder = base_folder / 'dataset1/NP1' -.. code:: ipython +.. code:: ipython3 + + base_folder = Path("/mnt/data/sam/DataSpikeSorting/imposed_motion_nick") + dataset_folder = base_folder / "dataset1/NP1" + +.. code:: ipython3 # read the file raw_rec = si.read_spikeglx(dataset_folder) @@ -66,10 +69,1045 @@ Here we will use *dataset1* with *neuropixel1*. This dataset is the -.. parsed-literal:: - - SpikeGLXRecordingExtractor: 384 channels - 30.0kHz - 1 segments - 58,715,724 samples - 1,957.19s (32.62 minutes) - int16 dtype - 42.00 GiB +.. raw:: html + +
SpikeGLXRecordingExtractor: 384 channels - 30.0kHz - 1 segments - 58,715,724 samples - 1,957.19s (32.62 minutes) - int16 dtype - 42.00 GiB
Channel IDs
    ['imec0.ap#AP0' 'imec0.ap#AP1' 'imec0.ap#AP2' 'imec0.ap#AP3' + 'imec0.ap#AP4' 'imec0.ap#AP5' 'imec0.ap#AP6' 'imec0.ap#AP7' + 'imec0.ap#AP8' 'imec0.ap#AP9' 'imec0.ap#AP10' 'imec0.ap#AP11' + 'imec0.ap#AP12' 'imec0.ap#AP13' 'imec0.ap#AP14' 'imec0.ap#AP15' + 'imec0.ap#AP16' 'imec0.ap#AP17' 'imec0.ap#AP18' 'imec0.ap#AP19' + 'imec0.ap#AP20' 'imec0.ap#AP21' 'imec0.ap#AP22' 'imec0.ap#AP23' + 'imec0.ap#AP24' 'imec0.ap#AP25' 'imec0.ap#AP26' 'imec0.ap#AP27' + 'imec0.ap#AP28' 'imec0.ap#AP29' 'imec0.ap#AP30' 'imec0.ap#AP31' + 'imec0.ap#AP32' 'imec0.ap#AP33' 'imec0.ap#AP34' 'imec0.ap#AP35' + 'imec0.ap#AP36' 'imec0.ap#AP37' 'imec0.ap#AP38' 'imec0.ap#AP39' + 'imec0.ap#AP40' 'imec0.ap#AP41' 'imec0.ap#AP42' 'imec0.ap#AP43' + 'imec0.ap#AP44' 'imec0.ap#AP45' 'imec0.ap#AP46' 'imec0.ap#AP47' + 'imec0.ap#AP48' 'imec0.ap#AP49' 'imec0.ap#AP50' 'imec0.ap#AP51' + 'imec0.ap#AP52' 'imec0.ap#AP53' 'imec0.ap#AP54' 'imec0.ap#AP55' + 'imec0.ap#AP56' 'imec0.ap#AP57' 'imec0.ap#AP58' 'imec0.ap#AP59' + 'imec0.ap#AP60' 'imec0.ap#AP61' 'imec0.ap#AP62' 'imec0.ap#AP63' + 'imec0.ap#AP64' 'imec0.ap#AP65' 'imec0.ap#AP66' 'imec0.ap#AP67' + 'imec0.ap#AP68' 'imec0.ap#AP69' 'imec0.ap#AP70' 'imec0.ap#AP71' + 'imec0.ap#AP72' 'imec0.ap#AP73' 'imec0.ap#AP74' 'imec0.ap#AP75' + 'imec0.ap#AP76' 'imec0.ap#AP77' 'imec0.ap#AP78' 'imec0.ap#AP79' + 'imec0.ap#AP80' 'imec0.ap#AP81' 'imec0.ap#AP82' 'imec0.ap#AP83' + 'imec0.ap#AP84' 'imec0.ap#AP85' 'imec0.ap#AP86' 'imec0.ap#AP87' + 'imec0.ap#AP88' 'imec0.ap#AP89' 'imec0.ap#AP90' 'imec0.ap#AP91' + 'imec0.ap#AP92' 'imec0.ap#AP93' 'imec0.ap#AP94' 'imec0.ap#AP95' + 'imec0.ap#AP96' 'imec0.ap#AP97' 'imec0.ap#AP98' 'imec0.ap#AP99' + 'imec0.ap#AP100' 'imec0.ap#AP101' 'imec0.ap#AP102' 'imec0.ap#AP103' + 'imec0.ap#AP104' 'imec0.ap#AP105' 'imec0.ap#AP106' 'imec0.ap#AP107' + 'imec0.ap#AP108' 'imec0.ap#AP109' 'imec0.ap#AP110' 'imec0.ap#AP111' + 'imec0.ap#AP112' 'imec0.ap#AP113' 'imec0.ap#AP114' 'imec0.ap#AP115' + 'imec0.ap#AP116' 'imec0.ap#AP117' 'imec0.ap#AP118' 'imec0.ap#AP119' + 'imec0.ap#AP120' 'imec0.ap#AP121' 'imec0.ap#AP122' 'imec0.ap#AP123' + 'imec0.ap#AP124' 'imec0.ap#AP125' 'imec0.ap#AP126' 'imec0.ap#AP127' + 'imec0.ap#AP128' 'imec0.ap#AP129' 'imec0.ap#AP130' 'imec0.ap#AP131' + 'imec0.ap#AP132' 'imec0.ap#AP133' 'imec0.ap#AP134' 'imec0.ap#AP135' + 'imec0.ap#AP136' 'imec0.ap#AP137' 'imec0.ap#AP138' 'imec0.ap#AP139' + 'imec0.ap#AP140' 'imec0.ap#AP141' 'imec0.ap#AP142' 'imec0.ap#AP143' + 'imec0.ap#AP144' 'imec0.ap#AP145' 'imec0.ap#AP146' 'imec0.ap#AP147' + 'imec0.ap#AP148' 'imec0.ap#AP149' 'imec0.ap#AP150' 'imec0.ap#AP151' + 'imec0.ap#AP152' 'imec0.ap#AP153' 'imec0.ap#AP154' 'imec0.ap#AP155' + 'imec0.ap#AP156' 'imec0.ap#AP157' 'imec0.ap#AP158' 'imec0.ap#AP159' + 'imec0.ap#AP160' 'imec0.ap#AP161' 'imec0.ap#AP162' 'imec0.ap#AP163' + 'imec0.ap#AP164' 'imec0.ap#AP165' 'imec0.ap#AP166' 'imec0.ap#AP167' + 'imec0.ap#AP168' 'imec0.ap#AP169' 'imec0.ap#AP170' 'imec0.ap#AP171' + 'imec0.ap#AP172' 'imec0.ap#AP173' 'imec0.ap#AP174' 'imec0.ap#AP175' + 'imec0.ap#AP176' 'imec0.ap#AP177' 'imec0.ap#AP178' 'imec0.ap#AP179' + 'imec0.ap#AP180' 'imec0.ap#AP181' 'imec0.ap#AP182' 'imec0.ap#AP183' + 'imec0.ap#AP184' 'imec0.ap#AP185' 'imec0.ap#AP186' 'imec0.ap#AP187' + 'imec0.ap#AP188' 'imec0.ap#AP189' 'imec0.ap#AP190' 'imec0.ap#AP191' + 'imec0.ap#AP192' 'imec0.ap#AP193' 'imec0.ap#AP194' 'imec0.ap#AP195' + 'imec0.ap#AP196' 'imec0.ap#AP197' 'imec0.ap#AP198' 'imec0.ap#AP199' + 'imec0.ap#AP200' 'imec0.ap#AP201' 'imec0.ap#AP202' 'imec0.ap#AP203' + 'imec0.ap#AP204' 'imec0.ap#AP205' 'imec0.ap#AP206' 'imec0.ap#AP207' + 'imec0.ap#AP208' 'imec0.ap#AP209' 'imec0.ap#AP210' 'imec0.ap#AP211' + 'imec0.ap#AP212' 'imec0.ap#AP213' 'imec0.ap#AP214' 'imec0.ap#AP215' + 'imec0.ap#AP216' 'imec0.ap#AP217' 'imec0.ap#AP218' 'imec0.ap#AP219' + 'imec0.ap#AP220' 'imec0.ap#AP221' 'imec0.ap#AP222' 'imec0.ap#AP223' + 'imec0.ap#AP224' 'imec0.ap#AP225' 'imec0.ap#AP226' 'imec0.ap#AP227' + 'imec0.ap#AP228' 'imec0.ap#AP229' 'imec0.ap#AP230' 'imec0.ap#AP231' + 'imec0.ap#AP232' 'imec0.ap#AP233' 'imec0.ap#AP234' 'imec0.ap#AP235' + 'imec0.ap#AP236' 'imec0.ap#AP237' 'imec0.ap#AP238' 'imec0.ap#AP239' + 'imec0.ap#AP240' 'imec0.ap#AP241' 'imec0.ap#AP242' 'imec0.ap#AP243' + 'imec0.ap#AP244' 'imec0.ap#AP245' 'imec0.ap#AP246' 'imec0.ap#AP247' + 'imec0.ap#AP248' 'imec0.ap#AP249' 'imec0.ap#AP250' 'imec0.ap#AP251' + 'imec0.ap#AP252' 'imec0.ap#AP253' 'imec0.ap#AP254' 'imec0.ap#AP255' + 'imec0.ap#AP256' 'imec0.ap#AP257' 'imec0.ap#AP258' 'imec0.ap#AP259' + 'imec0.ap#AP260' 'imec0.ap#AP261' 'imec0.ap#AP262' 'imec0.ap#AP263' + 'imec0.ap#AP264' 'imec0.ap#AP265' 'imec0.ap#AP266' 'imec0.ap#AP267' + 'imec0.ap#AP268' 'imec0.ap#AP269' 'imec0.ap#AP270' 'imec0.ap#AP271' + 'imec0.ap#AP272' 'imec0.ap#AP273' 'imec0.ap#AP274' 'imec0.ap#AP275' + 'imec0.ap#AP276' 'imec0.ap#AP277' 'imec0.ap#AP278' 'imec0.ap#AP279' + 'imec0.ap#AP280' 'imec0.ap#AP281' 'imec0.ap#AP282' 'imec0.ap#AP283' + 'imec0.ap#AP284' 'imec0.ap#AP285' 'imec0.ap#AP286' 'imec0.ap#AP287' + 'imec0.ap#AP288' 'imec0.ap#AP289' 'imec0.ap#AP290' 'imec0.ap#AP291' + 'imec0.ap#AP292' 'imec0.ap#AP293' 'imec0.ap#AP294' 'imec0.ap#AP295' + 'imec0.ap#AP296' 'imec0.ap#AP297' 'imec0.ap#AP298' 'imec0.ap#AP299' + 'imec0.ap#AP300' 'imec0.ap#AP301' 'imec0.ap#AP302' 'imec0.ap#AP303' + 'imec0.ap#AP304' 'imec0.ap#AP305' 'imec0.ap#AP306' 'imec0.ap#AP307' + 'imec0.ap#AP308' 'imec0.ap#AP309' 'imec0.ap#AP310' 'imec0.ap#AP311' + 'imec0.ap#AP312' 'imec0.ap#AP313' 'imec0.ap#AP314' 'imec0.ap#AP315' + 'imec0.ap#AP316' 'imec0.ap#AP317' 'imec0.ap#AP318' 'imec0.ap#AP319' + 'imec0.ap#AP320' 'imec0.ap#AP321' 'imec0.ap#AP322' 'imec0.ap#AP323' + 'imec0.ap#AP324' 'imec0.ap#AP325' 'imec0.ap#AP326' 'imec0.ap#AP327' + 'imec0.ap#AP328' 'imec0.ap#AP329' 'imec0.ap#AP330' 'imec0.ap#AP331' + 'imec0.ap#AP332' 'imec0.ap#AP333' 'imec0.ap#AP334' 'imec0.ap#AP335' + 'imec0.ap#AP336' 'imec0.ap#AP337' 'imec0.ap#AP338' 'imec0.ap#AP339' + 'imec0.ap#AP340' 'imec0.ap#AP341' 'imec0.ap#AP342' 'imec0.ap#AP343' + 'imec0.ap#AP344' 'imec0.ap#AP345' 'imec0.ap#AP346' 'imec0.ap#AP347' + 'imec0.ap#AP348' 'imec0.ap#AP349' 'imec0.ap#AP350' 'imec0.ap#AP351' + 'imec0.ap#AP352' 'imec0.ap#AP353' 'imec0.ap#AP354' 'imec0.ap#AP355' + 'imec0.ap#AP356' 'imec0.ap#AP357' 'imec0.ap#AP358' 'imec0.ap#AP359' + 'imec0.ap#AP360' 'imec0.ap#AP361' 'imec0.ap#AP362' 'imec0.ap#AP363' + 'imec0.ap#AP364' 'imec0.ap#AP365' 'imec0.ap#AP366' 'imec0.ap#AP367' + 'imec0.ap#AP368' 'imec0.ap#AP369' 'imec0.ap#AP370' 'imec0.ap#AP371' + 'imec0.ap#AP372' 'imec0.ap#AP373' 'imec0.ap#AP374' 'imec0.ap#AP375' + 'imec0.ap#AP376' 'imec0.ap#AP377' 'imec0.ap#AP378' 'imec0.ap#AP379' + 'imec0.ap#AP380' 'imec0.ap#AP381' 'imec0.ap#AP382' 'imec0.ap#AP383']
Annotations
  • is_filtered : False
  • probe_0_planar_contour : [[ -11 9989] + [ -11 -11] + [ 24 -186] + [ 59 -11] + [ 59 9989]]
  • probes_info : [{'model_name': 'Neuropixels 1.0', 'manufacturer': 'IMEC', 'probe_type': '0', 'serial_number': '18408406612', 'part_number': 'PRB_1_4_0480_1_C', 'port': '1', 'slot': '2'}]
Channel Properties
    gain_to_uV [2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375 + 2.34375 2.34375 2.34375 2.34375 2.34375 2.34375]
    offset_to_uV [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. + 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
    channel_names ['AP0' 'AP1' 'AP2' 'AP3' 'AP4' 'AP5' 'AP6' 'AP7' 'AP8' 'AP9' 'AP10' 'AP11' + 'AP12' 'AP13' 'AP14' 'AP15' 'AP16' 'AP17' 'AP18' 'AP19' 'AP20' 'AP21' + 'AP22' 'AP23' 'AP24' 'AP25' 'AP26' 'AP27' 'AP28' 'AP29' 'AP30' 'AP31' + 'AP32' 'AP33' 'AP34' 'AP35' 'AP36' 'AP37' 'AP38' 'AP39' 'AP40' 'AP41' + 'AP42' 'AP43' 'AP44' 'AP45' 'AP46' 'AP47' 'AP48' 'AP49' 'AP50' 'AP51' + 'AP52' 'AP53' 'AP54' 'AP55' 'AP56' 'AP57' 'AP58' 'AP59' 'AP60' 'AP61' + 'AP62' 'AP63' 'AP64' 'AP65' 'AP66' 'AP67' 'AP68' 'AP69' 'AP70' 'AP71' + 'AP72' 'AP73' 'AP74' 'AP75' 'AP76' 'AP77' 'AP78' 'AP79' 'AP80' 'AP81' + 'AP82' 'AP83' 'AP84' 'AP85' 'AP86' 'AP87' 'AP88' 'AP89' 'AP90' 'AP91' + 'AP92' 'AP93' 'AP94' 'AP95' 'AP96' 'AP97' 'AP98' 'AP99' 'AP100' 'AP101' + 'AP102' 'AP103' 'AP104' 'AP105' 'AP106' 'AP107' 'AP108' 'AP109' 'AP110' + 'AP111' 'AP112' 'AP113' 'AP114' 'AP115' 'AP116' 'AP117' 'AP118' 'AP119' + 'AP120' 'AP121' 'AP122' 'AP123' 'AP124' 'AP125' 'AP126' 'AP127' 'AP128' + 'AP129' 'AP130' 'AP131' 'AP132' 'AP133' 'AP134' 'AP135' 'AP136' 'AP137' + 'AP138' 'AP139' 'AP140' 'AP141' 'AP142' 'AP143' 'AP144' 'AP145' 'AP146' + 'AP147' 'AP148' 'AP149' 'AP150' 'AP151' 'AP152' 'AP153' 'AP154' 'AP155' + 'AP156' 'AP157' 'AP158' 'AP159' 'AP160' 'AP161' 'AP162' 'AP163' 'AP164' + 'AP165' 'AP166' 'AP167' 'AP168' 'AP169' 'AP170' 'AP171' 'AP172' 'AP173' + 'AP174' 'AP175' 'AP176' 'AP177' 'AP178' 'AP179' 'AP180' 'AP181' 'AP182' + 'AP183' 'AP184' 'AP185' 'AP186' 'AP187' 'AP188' 'AP189' 'AP190' 'AP191' + 'AP192' 'AP193' 'AP194' 'AP195' 'AP196' 'AP197' 'AP198' 'AP199' 'AP200' + 'AP201' 'AP202' 'AP203' 'AP204' 'AP205' 'AP206' 'AP207' 'AP208' 'AP209' + 'AP210' 'AP211' 'AP212' 'AP213' 'AP214' 'AP215' 'AP216' 'AP217' 'AP218' + 'AP219' 'AP220' 'AP221' 'AP222' 'AP223' 'AP224' 'AP225' 'AP226' 'AP227' + 'AP228' 'AP229' 'AP230' 'AP231' 'AP232' 'AP233' 'AP234' 'AP235' 'AP236' + 'AP237' 'AP238' 'AP239' 'AP240' 'AP241' 'AP242' 'AP243' 'AP244' 'AP245' + 'AP246' 'AP247' 'AP248' 'AP249' 'AP250' 'AP251' 'AP252' 'AP253' 'AP254' + 'AP255' 'AP256' 'AP257' 'AP258' 'AP259' 'AP260' 'AP261' 'AP262' 'AP263' + 'AP264' 'AP265' 'AP266' 'AP267' 'AP268' 'AP269' 'AP270' 'AP271' 'AP272' + 'AP273' 'AP274' 'AP275' 'AP276' 'AP277' 'AP278' 'AP279' 'AP280' 'AP281' + 'AP282' 'AP283' 'AP284' 'AP285' 'AP286' 'AP287' 'AP288' 'AP289' 'AP290' + 'AP291' 'AP292' 'AP293' 'AP294' 'AP295' 'AP296' 'AP297' 'AP298' 'AP299' + 'AP300' 'AP301' 'AP302' 'AP303' 'AP304' 'AP305' 'AP306' 'AP307' 'AP308' + 'AP309' 'AP310' 'AP311' 'AP312' 'AP313' 'AP314' 'AP315' 'AP316' 'AP317' + 'AP318' 'AP319' 'AP320' 'AP321' 'AP322' 'AP323' 'AP324' 'AP325' 'AP326' + 'AP327' 'AP328' 'AP329' 'AP330' 'AP331' 'AP332' 'AP333' 'AP334' 'AP335' + 'AP336' 'AP337' 'AP338' 'AP339' 'AP340' 'AP341' 'AP342' 'AP343' 'AP344' + 'AP345' 'AP346' 'AP347' 'AP348' 'AP349' 'AP350' 'AP351' 'AP352' 'AP353' + 'AP354' 'AP355' 'AP356' 'AP357' 'AP358' 'AP359' 'AP360' 'AP361' 'AP362' + 'AP363' 'AP364' 'AP365' 'AP366' 'AP367' 'AP368' 'AP369' 'AP370' 'AP371' + 'AP372' 'AP373' 'AP374' 'AP375' 'AP376' 'AP377' 'AP378' 'AP379' 'AP380' + 'AP381' 'AP382' 'AP383']
    contact_vector [(0, 16., 0., 'square', 12., '', 'e0', 0, 'um', 1., 0., 0., 1., 0, 0, 0, 500, 250, 1) + (0, 48., 0., 'square', 12., '', 'e1', 1, 'um', 1., 0., 0., 1., 1, 0, 0, 500, 250, 1) + (0, 0., 20., 'square', 12., '', 'e2', 2, 'um', 1., 0., 0., 1., 2, 0, 0, 500, 250, 1) + (0, 32., 20., 'square', 12., '', 'e3', 3, 'um', 1., 0., 0., 1., 3, 0, 0, 500, 250, 1) + (0, 16., 40., 'square', 12., '', 'e4', 4, 'um', 1., 0., 0., 1., 4, 0, 0, 500, 250, 1) + (0, 48., 40., 'square', 12., '', 'e5', 5, 'um', 1., 0., 0., 1., 5, 0, 0, 500, 250, 1) + (0, 0., 60., 'square', 12., '', 'e6', 6, 'um', 1., 0., 0., 1., 6, 0, 0, 500, 250, 1) + (0, 32., 60., 'square', 12., '', 'e7', 7, 'um', 1., 0., 0., 1., 7, 0, 0, 500, 250, 1) + (0, 16., 80., 'square', 12., '', 'e8', 8, 'um', 1., 0., 0., 1., 8, 0, 0, 500, 250, 1) + (0, 48., 80., 'square', 12., '', 'e9', 9, 'um', 1., 0., 0., 1., 9, 0, 0, 500, 250, 1) + (0, 0., 100., 'square', 12., '', 'e10', 10, 'um', 1., 0., 0., 1., 10, 0, 0, 500, 250, 1) + (0, 32., 100., 'square', 12., '', 'e11', 11, 'um', 1., 0., 0., 1., 11, 0, 0, 500, 250, 1) + (0, 16., 120., 'square', 12., '', 'e12', 12, 'um', 1., 0., 0., 1., 12, 0, 0, 500, 250, 1) + (0, 48., 120., 'square', 12., '', 'e13', 13, 'um', 1., 0., 0., 1., 13, 0, 0, 500, 250, 1) + (0, 0., 140., 'square', 12., '', 'e14', 14, 'um', 1., 0., 0., 1., 14, 0, 0, 500, 250, 1) + (0, 32., 140., 'square', 12., '', 'e15', 15, 'um', 1., 0., 0., 1., 15, 0, 0, 500, 250, 1) + (0, 16., 160., 'square', 12., '', 'e16', 16, 'um', 1., 0., 0., 1., 16, 0, 0, 500, 250, 1) + (0, 48., 160., 'square', 12., '', 'e17', 17, 'um', 1., 0., 0., 1., 17, 0, 0, 500, 250, 1) + (0, 0., 180., 'square', 12., '', 'e18', 18, 'um', 1., 0., 0., 1., 18, 0, 0, 500, 250, 1) + (0, 32., 180., 'square', 12., '', 'e19', 19, 'um', 1., 0., 0., 1., 19, 0, 0, 500, 250, 1) + (0, 16., 200., 'square', 12., '', 'e20', 20, 'um', 1., 0., 0., 1., 20, 0, 0, 500, 250, 1) + (0, 48., 200., 'square', 12., '', 'e21', 21, 'um', 1., 0., 0., 1., 21, 0, 0, 500, 250, 1) + (0, 0., 220., 'square', 12., '', 'e22', 22, 'um', 1., 0., 0., 1., 22, 0, 0, 500, 250, 1) + (0, 32., 220., 'square', 12., '', 'e23', 23, 'um', 1., 0., 0., 1., 23, 0, 0, 500, 250, 1) + (0, 16., 240., 'square', 12., '', 'e24', 24, 'um', 1., 0., 0., 1., 24, 0, 0, 500, 250, 1) + (0, 48., 240., 'square', 12., '', 'e25', 25, 'um', 1., 0., 0., 1., 25, 0, 0, 500, 250, 1) + (0, 0., 260., 'square', 12., '', 'e26', 26, 'um', 1., 0., 0., 1., 26, 0, 0, 500, 250, 1) + (0, 32., 260., 'square', 12., '', 'e27', 27, 'um', 1., 0., 0., 1., 27, 0, 0, 500, 250, 1) + (0, 16., 280., 'square', 12., '', 'e28', 28, 'um', 1., 0., 0., 1., 28, 0, 0, 500, 250, 1) + (0, 48., 280., 'square', 12., '', 'e29', 29, 'um', 1., 0., 0., 1., 29, 0, 0, 500, 250, 1) + (0, 0., 300., 'square', 12., '', 'e30', 30, 'um', 1., 0., 0., 1., 30, 0, 0, 500, 250, 1) + (0, 32., 300., 'square', 12., '', 'e31', 31, 'um', 1., 0., 0., 1., 31, 0, 0, 500, 250, 1) + (0, 16., 320., 'square', 12., '', 'e32', 32, 'um', 1., 0., 0., 1., 32, 0, 0, 500, 250, 1) + (0, 48., 320., 'square', 12., '', 'e33', 33, 'um', 1., 0., 0., 1., 33, 0, 0, 500, 250, 1) + (0, 0., 340., 'square', 12., '', 'e34', 34, 'um', 1., 0., 0., 1., 34, 0, 0, 500, 250, 1) + (0, 32., 340., 'square', 12., '', 'e35', 35, 'um', 1., 0., 0., 1., 35, 0, 0, 500, 250, 1) + (0, 16., 360., 'square', 12., '', 'e36', 36, 'um', 1., 0., 0., 1., 36, 0, 0, 500, 250, 1) + (0, 48., 360., 'square', 12., '', 'e37', 37, 'um', 1., 0., 0., 1., 37, 0, 0, 500, 250, 1) + (0, 0., 380., 'square', 12., '', 'e38', 38, 'um', 1., 0., 0., 1., 38, 0, 0, 500, 250, 1) + (0, 32., 380., 'square', 12., '', 'e39', 39, 'um', 1., 0., 0., 1., 39, 0, 0, 500, 250, 1) + (0, 16., 400., 'square', 12., '', 'e40', 40, 'um', 1., 0., 0., 1., 40, 0, 0, 500, 250, 1) + (0, 48., 400., 'square', 12., '', 'e41', 41, 'um', 1., 0., 0., 1., 41, 0, 0, 500, 250, 1) + (0, 0., 420., 'square', 12., '', 'e42', 42, 'um', 1., 0., 0., 1., 42, 0, 0, 500, 250, 1) + (0, 32., 420., 'square', 12., '', 'e43', 43, 'um', 1., 0., 0., 1., 43, 0, 0, 500, 250, 1) + (0, 16., 440., 'square', 12., '', 'e44', 44, 'um', 1., 0., 0., 1., 44, 0, 0, 500, 250, 1) + (0, 48., 440., 'square', 12., '', 'e45', 45, 'um', 1., 0., 0., 1., 45, 0, 0, 500, 250, 1) + (0, 0., 460., 'square', 12., '', 'e46', 46, 'um', 1., 0., 0., 1., 46, 0, 0, 500, 250, 1) + (0, 32., 460., 'square', 12., '', 'e47', 47, 'um', 1., 0., 0., 1., 47, 0, 0, 500, 250, 1) + (0, 16., 480., 'square', 12., '', 'e48', 48, 'um', 1., 0., 0., 1., 48, 0, 0, 500, 250, 1) + (0, 48., 480., 'square', 12., '', 'e49', 49, 'um', 1., 0., 0., 1., 49, 0, 0, 500, 250, 1) + (0, 0., 500., 'square', 12., '', 'e50', 50, 'um', 1., 0., 0., 1., 50, 0, 0, 500, 250, 1) + (0, 32., 500., 'square', 12., '', 'e51', 51, 'um', 1., 0., 0., 1., 51, 0, 0, 500, 250, 1) + (0, 16., 520., 'square', 12., '', 'e52', 52, 'um', 1., 0., 0., 1., 52, 0, 0, 500, 250, 1) + (0, 48., 520., 'square', 12., '', 'e53', 53, 'um', 1., 0., 0., 1., 53, 0, 0, 500, 250, 1) + (0, 0., 540., 'square', 12., '', 'e54', 54, 'um', 1., 0., 0., 1., 54, 0, 0, 500, 250, 1) + (0, 32., 540., 'square', 12., '', 'e55', 55, 'um', 1., 0., 0., 1., 55, 0, 0, 500, 250, 1) + (0, 16., 560., 'square', 12., '', 'e56', 56, 'um', 1., 0., 0., 1., 56, 0, 0, 500, 250, 1) + (0, 48., 560., 'square', 12., '', 'e57', 57, 'um', 1., 0., 0., 1., 57, 0, 0, 500, 250, 1) + (0, 0., 580., 'square', 12., '', 'e58', 58, 'um', 1., 0., 0., 1., 58, 0, 0, 500, 250, 1) + (0, 32., 580., 'square', 12., '', 'e59', 59, 'um', 1., 0., 0., 1., 59, 0, 0, 500, 250, 1) + (0, 16., 600., 'square', 12., '', 'e60', 60, 'um', 1., 0., 0., 1., 60, 0, 0, 500, 250, 1) + (0, 48., 600., 'square', 12., '', 'e61', 61, 'um', 1., 0., 0., 1., 61, 0, 0, 500, 250, 1) + (0, 0., 620., 'square', 12., '', 'e62', 62, 'um', 1., 0., 0., 1., 62, 0, 0, 500, 250, 1) + (0, 32., 620., 'square', 12., '', 'e63', 63, 'um', 1., 0., 0., 1., 63, 0, 0, 500, 250, 1) + (0, 16., 640., 'square', 12., '', 'e64', 64, 'um', 1., 0., 0., 1., 64, 0, 0, 500, 250, 1) + (0, 48., 640., 'square', 12., '', 'e65', 65, 'um', 1., 0., 0., 1., 65, 0, 0, 500, 250, 1) + (0, 0., 660., 'square', 12., '', 'e66', 66, 'um', 1., 0., 0., 1., 66, 0, 0, 500, 250, 1) + (0, 32., 660., 'square', 12., '', 'e67', 67, 'um', 1., 0., 0., 1., 67, 0, 0, 500, 250, 1) + (0, 16., 680., 'square', 12., '', 'e68', 68, 'um', 1., 0., 0., 1., 68, 0, 0, 500, 250, 1) + (0, 48., 680., 'square', 12., '', 'e69', 69, 'um', 1., 0., 0., 1., 69, 0, 0, 500, 250, 1) + (0, 0., 700., 'square', 12., '', 'e70', 70, 'um', 1., 0., 0., 1., 70, 0, 0, 500, 250, 1) + (0, 32., 700., 'square', 12., '', 'e71', 71, 'um', 1., 0., 0., 1., 71, 0, 0, 500, 250, 1) + (0, 16., 720., 'square', 12., '', 'e72', 72, 'um', 1., 0., 0., 1., 72, 0, 0, 500, 250, 1) + (0, 48., 720., 'square', 12., '', 'e73', 73, 'um', 1., 0., 0., 1., 73, 0, 0, 500, 250, 1) + (0, 0., 740., 'square', 12., '', 'e74', 74, 'um', 1., 0., 0., 1., 74, 0, 0, 500, 250, 1) + (0, 32., 740., 'square', 12., '', 'e75', 75, 'um', 1., 0., 0., 1., 75, 0, 0, 500, 250, 1) + (0, 16., 760., 'square', 12., '', 'e76', 76, 'um', 1., 0., 0., 1., 76, 0, 0, 500, 250, 1) + (0, 48., 760., 'square', 12., '', 'e77', 77, 'um', 1., 0., 0., 1., 77, 0, 0, 500, 250, 1) + (0, 0., 780., 'square', 12., '', 'e78', 78, 'um', 1., 0., 0., 1., 78, 0, 0, 500, 250, 1) + (0, 32., 780., 'square', 12., '', 'e79', 79, 'um', 1., 0., 0., 1., 79, 0, 0, 500, 250, 1) + (0, 16., 800., 'square', 12., '', 'e80', 80, 'um', 1., 0., 0., 1., 80, 0, 0, 500, 250, 1) + (0, 48., 800., 'square', 12., '', 'e81', 81, 'um', 1., 0., 0., 1., 81, 0, 0, 500, 250, 1) + (0, 0., 820., 'square', 12., '', 'e82', 82, 'um', 1., 0., 0., 1., 82, 0, 0, 500, 250, 1) + (0, 32., 820., 'square', 12., '', 'e83', 83, 'um', 1., 0., 0., 1., 83, 0, 0, 500, 250, 1) + (0, 16., 840., 'square', 12., '', 'e84', 84, 'um', 1., 0., 0., 1., 84, 0, 0, 500, 250, 1) + (0, 48., 840., 'square', 12., '', 'e85', 85, 'um', 1., 0., 0., 1., 85, 0, 0, 500, 250, 1) + (0, 0., 860., 'square', 12., '', 'e86', 86, 'um', 1., 0., 0., 1., 86, 0, 0, 500, 250, 1) + (0, 32., 860., 'square', 12., '', 'e87', 87, 'um', 1., 0., 0., 1., 87, 0, 0, 500, 250, 1) + (0, 16., 880., 'square', 12., '', 'e88', 88, 'um', 1., 0., 0., 1., 88, 0, 0, 500, 250, 1) + (0, 48., 880., 'square', 12., '', 'e89', 89, 'um', 1., 0., 0., 1., 89, 0, 0, 500, 250, 1) + (0, 0., 900., 'square', 12., '', 'e90', 90, 'um', 1., 0., 0., 1., 90, 0, 0, 500, 250, 1) + (0, 32., 900., 'square', 12., '', 'e91', 91, 'um', 1., 0., 0., 1., 91, 0, 0, 500, 250, 1) + (0, 16., 920., 'square', 12., '', 'e92', 92, 'um', 1., 0., 0., 1., 92, 0, 0, 500, 250, 1) + (0, 48., 920., 'square', 12., '', 'e93', 93, 'um', 1., 0., 0., 1., 93, 0, 0, 500, 250, 1) + (0, 0., 940., 'square', 12., '', 'e94', 94, 'um', 1., 0., 0., 1., 94, 0, 0, 500, 250, 1) + (0, 32., 940., 'square', 12., '', 'e95', 95, 'um', 1., 0., 0., 1., 95, 0, 0, 500, 250, 1) + (0, 16., 960., 'square', 12., '', 'e96', 96, 'um', 1., 0., 0., 1., 96, 0, 0, 500, 250, 1) + (0, 48., 960., 'square', 12., '', 'e97', 97, 'um', 1., 0., 0., 1., 97, 0, 0, 500, 250, 1) + (0, 0., 980., 'square', 12., '', 'e98', 98, 'um', 1., 0., 0., 1., 98, 0, 0, 500, 250, 1) + (0, 32., 980., 'square', 12., '', 'e99', 99, 'um', 1., 0., 0., 1., 99, 0, 0, 500, 250, 1) + (0, 16., 1000., 'square', 12., '', 'e100', 100, 'um', 1., 0., 0., 1., 100, 0, 0, 500, 250, 1) + (0, 48., 1000., 'square', 12., '', 'e101', 101, 'um', 1., 0., 0., 1., 101, 0, 0, 500, 250, 1) + (0, 0., 1020., 'square', 12., '', 'e102', 102, 'um', 1., 0., 0., 1., 102, 0, 0, 500, 250, 1) + (0, 32., 1020., 'square', 12., '', 'e103', 103, 'um', 1., 0., 0., 1., 103, 0, 0, 500, 250, 1) + (0, 16., 1040., 'square', 12., '', 'e104', 104, 'um', 1., 0., 0., 1., 104, 0, 0, 500, 250, 1) + (0, 48., 1040., 'square', 12., '', 'e105', 105, 'um', 1., 0., 0., 1., 105, 0, 0, 500, 250, 1) + (0, 0., 1060., 'square', 12., '', 'e106', 106, 'um', 1., 0., 0., 1., 106, 0, 0, 500, 250, 1) + (0, 32., 1060., 'square', 12., '', 'e107', 107, 'um', 1., 0., 0., 1., 107, 0, 0, 500, 250, 1) + (0, 16., 1080., 'square', 12., '', 'e108', 108, 'um', 1., 0., 0., 1., 108, 0, 0, 500, 250, 1) + (0, 48., 1080., 'square', 12., '', 'e109', 109, 'um', 1., 0., 0., 1., 109, 0, 0, 500, 250, 1) + (0, 0., 1100., 'square', 12., '', 'e110', 110, 'um', 1., 0., 0., 1., 110, 0, 0, 500, 250, 1) + (0, 32., 1100., 'square', 12., '', 'e111', 111, 'um', 1., 0., 0., 1., 111, 0, 0, 500, 250, 1) + (0, 16., 1120., 'square', 12., '', 'e112', 112, 'um', 1., 0., 0., 1., 112, 0, 0, 500, 250, 1) + (0, 48., 1120., 'square', 12., '', 'e113', 113, 'um', 1., 0., 0., 1., 113, 0, 0, 500, 250, 1) + (0, 0., 1140., 'square', 12., '', 'e114', 114, 'um', 1., 0., 0., 1., 114, 0, 0, 500, 250, 1) + (0, 32., 1140., 'square', 12., '', 'e115', 115, 'um', 1., 0., 0., 1., 115, 0, 0, 500, 250, 1) + (0, 16., 1160., 'square', 12., '', 'e116', 116, 'um', 1., 0., 0., 1., 116, 0, 0, 500, 250, 1) + (0, 48., 1160., 'square', 12., '', 'e117', 117, 'um', 1., 0., 0., 1., 117, 0, 0, 500, 250, 1) + (0, 0., 1180., 'square', 12., '', 'e118', 118, 'um', 1., 0., 0., 1., 118, 0, 0, 500, 250, 1) + (0, 32., 1180., 'square', 12., '', 'e119', 119, 'um', 1., 0., 0., 1., 119, 0, 0, 500, 250, 1) + (0, 16., 1200., 'square', 12., '', 'e120', 120, 'um', 1., 0., 0., 1., 120, 0, 0, 500, 250, 1) + (0, 48., 1200., 'square', 12., '', 'e121', 121, 'um', 1., 0., 0., 1., 121, 0, 0, 500, 250, 1) + (0, 0., 1220., 'square', 12., '', 'e122', 122, 'um', 1., 0., 0., 1., 122, 0, 0, 500, 250, 1) + (0, 32., 1220., 'square', 12., '', 'e123', 123, 'um', 1., 0., 0., 1., 123, 0, 0, 500, 250, 1) + (0, 16., 1240., 'square', 12., '', 'e124', 124, 'um', 1., 0., 0., 1., 124, 0, 0, 500, 250, 1) + (0, 48., 1240., 'square', 12., '', 'e125', 125, 'um', 1., 0., 0., 1., 125, 0, 0, 500, 250, 1) + (0, 0., 1260., 'square', 12., '', 'e126', 126, 'um', 1., 0., 0., 1., 126, 0, 0, 500, 250, 1) + (0, 32., 1260., 'square', 12., '', 'e127', 127, 'um', 1., 0., 0., 1., 127, 0, 0, 500, 250, 1) + (0, 16., 1280., 'square', 12., '', 'e128', 128, 'um', 1., 0., 0., 1., 128, 0, 0, 500, 250, 1) + (0, 48., 1280., 'square', 12., '', 'e129', 129, 'um', 1., 0., 0., 1., 129, 0, 0, 500, 250, 1) + (0, 0., 1300., 'square', 12., '', 'e130', 130, 'um', 1., 0., 0., 1., 130, 0, 0, 500, 250, 1) + (0, 32., 1300., 'square', 12., '', 'e131', 131, 'um', 1., 0., 0., 1., 131, 0, 0, 500, 250, 1) + (0, 16., 1320., 'square', 12., '', 'e132', 132, 'um', 1., 0., 0., 1., 132, 0, 0, 500, 250, 1) + (0, 48., 1320., 'square', 12., '', 'e133', 133, 'um', 1., 0., 0., 1., 133, 0, 0, 500, 250, 1) + (0, 0., 1340., 'square', 12., '', 'e134', 134, 'um', 1., 0., 0., 1., 134, 0, 0, 500, 250, 1) + (0, 32., 1340., 'square', 12., '', 'e135', 135, 'um', 1., 0., 0., 1., 135, 0, 0, 500, 250, 1) + (0, 16., 1360., 'square', 12., '', 'e136', 136, 'um', 1., 0., 0., 1., 136, 0, 0, 500, 250, 1) + (0, 48., 1360., 'square', 12., '', 'e137', 137, 'um', 1., 0., 0., 1., 137, 0, 0, 500, 250, 1) + (0, 0., 1380., 'square', 12., '', 'e138', 138, 'um', 1., 0., 0., 1., 138, 0, 0, 500, 250, 1) + (0, 32., 1380., 'square', 12., '', 'e139', 139, 'um', 1., 0., 0., 1., 139, 0, 0, 500, 250, 1) + (0, 16., 1400., 'square', 12., '', 'e140', 140, 'um', 1., 0., 0., 1., 140, 0, 0, 500, 250, 1) + (0, 48., 1400., 'square', 12., '', 'e141', 141, 'um', 1., 0., 0., 1., 141, 0, 0, 500, 250, 1) + (0, 0., 1420., 'square', 12., '', 'e142', 142, 'um', 1., 0., 0., 1., 142, 0, 0, 500, 250, 1) + (0, 32., 1420., 'square', 12., '', 'e143', 143, 'um', 1., 0., 0., 1., 143, 0, 0, 500, 250, 1) + (0, 16., 1440., 'square', 12., '', 'e144', 144, 'um', 1., 0., 0., 1., 144, 0, 0, 500, 250, 1) + (0, 48., 1440., 'square', 12., '', 'e145', 145, 'um', 1., 0., 0., 1., 145, 0, 0, 500, 250, 1) + (0, 0., 1460., 'square', 12., '', 'e146', 146, 'um', 1., 0., 0., 1., 146, 0, 0, 500, 250, 1) + (0, 32., 1460., 'square', 12., '', 'e147', 147, 'um', 1., 0., 0., 1., 147, 0, 0, 500, 250, 1) + (0, 16., 1480., 'square', 12., '', 'e148', 148, 'um', 1., 0., 0., 1., 148, 0, 0, 500, 250, 1) + (0, 48., 1480., 'square', 12., '', 'e149', 149, 'um', 1., 0., 0., 1., 149, 0, 0, 500, 250, 1) + (0, 0., 1500., 'square', 12., '', 'e150', 150, 'um', 1., 0., 0., 1., 150, 0, 0, 500, 250, 1) + (0, 32., 1500., 'square', 12., '', 'e151', 151, 'um', 1., 0., 0., 1., 151, 0, 0, 500, 250, 1) + (0, 16., 1520., 'square', 12., '', 'e152', 152, 'um', 1., 0., 0., 1., 152, 0, 0, 500, 250, 1) + (0, 48., 1520., 'square', 12., '', 'e153', 153, 'um', 1., 0., 0., 1., 153, 0, 0, 500, 250, 1) + (0, 0., 1540., 'square', 12., '', 'e154', 154, 'um', 1., 0., 0., 1., 154, 0, 0, 500, 250, 1) + (0, 32., 1540., 'square', 12., '', 'e155', 155, 'um', 1., 0., 0., 1., 155, 0, 0, 500, 250, 1) + (0, 16., 1560., 'square', 12., '', 'e156', 156, 'um', 1., 0., 0., 1., 156, 0, 0, 500, 250, 1) + (0, 48., 1560., 'square', 12., '', 'e157', 157, 'um', 1., 0., 0., 1., 157, 0, 0, 500, 250, 1) + (0, 0., 1580., 'square', 12., '', 'e158', 158, 'um', 1., 0., 0., 1., 158, 0, 0, 500, 250, 1) + (0, 32., 1580., 'square', 12., '', 'e159', 159, 'um', 1., 0., 0., 1., 159, 0, 0, 500, 250, 1) + (0, 16., 1600., 'square', 12., '', 'e160', 160, 'um', 1., 0., 0., 1., 160, 0, 0, 500, 250, 1) + (0, 48., 1600., 'square', 12., '', 'e161', 161, 'um', 1., 0., 0., 1., 161, 0, 0, 500, 250, 1) + (0, 0., 1620., 'square', 12., '', 'e162', 162, 'um', 1., 0., 0., 1., 162, 0, 0, 500, 250, 1) + (0, 32., 1620., 'square', 12., '', 'e163', 163, 'um', 1., 0., 0., 1., 163, 0, 0, 500, 250, 1) + (0, 16., 1640., 'square', 12., '', 'e164', 164, 'um', 1., 0., 0., 1., 164, 0, 0, 500, 250, 1) + (0, 48., 1640., 'square', 12., '', 'e165', 165, 'um', 1., 0., 0., 1., 165, 0, 0, 500, 250, 1) + (0, 0., 1660., 'square', 12., '', 'e166', 166, 'um', 1., 0., 0., 1., 166, 0, 0, 500, 250, 1) + (0, 32., 1660., 'square', 12., '', 'e167', 167, 'um', 1., 0., 0., 1., 167, 0, 0, 500, 250, 1) + (0, 16., 1680., 'square', 12., '', 'e168', 168, 'um', 1., 0., 0., 1., 168, 0, 0, 500, 250, 1) + (0, 48., 1680., 'square', 12., '', 'e169', 169, 'um', 1., 0., 0., 1., 169, 0, 0, 500, 250, 1) + (0, 0., 1700., 'square', 12., '', 'e170', 170, 'um', 1., 0., 0., 1., 170, 0, 0, 500, 250, 1) + (0, 32., 1700., 'square', 12., '', 'e171', 171, 'um', 1., 0., 0., 1., 171, 0, 0, 500, 250, 1) + (0, 16., 1720., 'square', 12., '', 'e172', 172, 'um', 1., 0., 0., 1., 172, 0, 0, 500, 250, 1) + (0, 48., 1720., 'square', 12., '', 'e173', 173, 'um', 1., 0., 0., 1., 173, 0, 0, 500, 250, 1) + (0, 0., 1740., 'square', 12., '', 'e174', 174, 'um', 1., 0., 0., 1., 174, 0, 0, 500, 250, 1) + (0, 32., 1740., 'square', 12., '', 'e175', 175, 'um', 1., 0., 0., 1., 175, 0, 0, 500, 250, 1) + (0, 16., 1760., 'square', 12., '', 'e176', 176, 'um', 1., 0., 0., 1., 176, 0, 0, 500, 250, 1) + (0, 48., 1760., 'square', 12., '', 'e177', 177, 'um', 1., 0., 0., 1., 177, 0, 0, 500, 250, 1) + (0, 0., 1780., 'square', 12., '', 'e178', 178, 'um', 1., 0., 0., 1., 178, 0, 0, 500, 250, 1) + (0, 32., 1780., 'square', 12., '', 'e179', 179, 'um', 1., 0., 0., 1., 179, 0, 0, 500, 250, 1) + (0, 16., 1800., 'square', 12., '', 'e180', 180, 'um', 1., 0., 0., 1., 180, 0, 0, 500, 250, 1) + (0, 48., 1800., 'square', 12., '', 'e181', 181, 'um', 1., 0., 0., 1., 181, 0, 0, 500, 250, 1) + (0, 0., 1820., 'square', 12., '', 'e182', 182, 'um', 1., 0., 0., 1., 182, 0, 0, 500, 250, 1) + (0, 32., 1820., 'square', 12., '', 'e183', 183, 'um', 1., 0., 0., 1., 183, 0, 0, 500, 250, 1) + (0, 16., 1840., 'square', 12., '', 'e184', 184, 'um', 1., 0., 0., 1., 184, 0, 0, 500, 250, 1) + (0, 48., 1840., 'square', 12., '', 'e185', 185, 'um', 1., 0., 0., 1., 185, 0, 0, 500, 250, 1) + (0, 0., 1860., 'square', 12., '', 'e186', 186, 'um', 1., 0., 0., 1., 186, 0, 0, 500, 250, 1) + (0, 32., 1860., 'square', 12., '', 'e187', 187, 'um', 1., 0., 0., 1., 187, 0, 0, 500, 250, 1) + (0, 16., 1880., 'square', 12., '', 'e188', 188, 'um', 1., 0., 0., 1., 188, 0, 0, 500, 250, 1) + (0, 48., 1880., 'square', 12., '', 'e189', 189, 'um', 1., 0., 0., 1., 189, 0, 0, 500, 250, 1) + (0, 0., 1900., 'square', 12., '', 'e190', 190, 'um', 1., 0., 0., 1., 190, 0, 0, 500, 250, 1) + (0, 32., 1900., 'square', 12., '', 'e191', 191, 'um', 1., 0., 0., 1., 191, 0, 0, 500, 250, 1) + (0, 16., 1920., 'square', 12., '', 'e192', 192, 'um', 1., 0., 0., 1., 192, 0, 0, 500, 250, 1) + (0, 48., 1920., 'square', 12., '', 'e193', 193, 'um', 1., 0., 0., 1., 193, 0, 0, 500, 250, 1) + (0, 0., 1940., 'square', 12., '', 'e194', 194, 'um', 1., 0., 0., 1., 194, 0, 0, 500, 250, 1) + (0, 32., 1940., 'square', 12., '', 'e195', 195, 'um', 1., 0., 0., 1., 195, 0, 0, 500, 250, 1) + (0, 16., 1960., 'square', 12., '', 'e196', 196, 'um', 1., 0., 0., 1., 196, 0, 0, 500, 250, 1) + (0, 48., 1960., 'square', 12., '', 'e197', 197, 'um', 1., 0., 0., 1., 197, 0, 0, 500, 250, 1) + (0, 0., 1980., 'square', 12., '', 'e198', 198, 'um', 1., 0., 0., 1., 198, 0, 0, 500, 250, 1) + (0, 32., 1980., 'square', 12., '', 'e199', 199, 'um', 1., 0., 0., 1., 199, 0, 0, 500, 250, 1) + (0, 16., 2000., 'square', 12., '', 'e200', 200, 'um', 1., 0., 0., 1., 200, 0, 0, 500, 250, 1) + (0, 48., 2000., 'square', 12., '', 'e201', 201, 'um', 1., 0., 0., 1., 201, 0, 0, 500, 250, 1) + (0, 0., 2020., 'square', 12., '', 'e202', 202, 'um', 1., 0., 0., 1., 202, 0, 0, 500, 250, 1) + (0, 32., 2020., 'square', 12., '', 'e203', 203, 'um', 1., 0., 0., 1., 203, 0, 0, 500, 250, 1) + (0, 16., 2040., 'square', 12., '', 'e204', 204, 'um', 1., 0., 0., 1., 204, 0, 0, 500, 250, 1) + (0, 48., 2040., 'square', 12., '', 'e205', 205, 'um', 1., 0., 0., 1., 205, 0, 0, 500, 250, 1) + (0, 0., 2060., 'square', 12., '', 'e206', 206, 'um', 1., 0., 0., 1., 206, 0, 0, 500, 250, 1) + (0, 32., 2060., 'square', 12., '', 'e207', 207, 'um', 1., 0., 0., 1., 207, 0, 0, 500, 250, 1) + (0, 16., 2080., 'square', 12., '', 'e208', 208, 'um', 1., 0., 0., 1., 208, 0, 0, 500, 250, 1) + (0, 48., 2080., 'square', 12., '', 'e209', 209, 'um', 1., 0., 0., 1., 209, 0, 0, 500, 250, 1) + (0, 0., 2100., 'square', 12., '', 'e210', 210, 'um', 1., 0., 0., 1., 210, 0, 0, 500, 250, 1) + (0, 32., 2100., 'square', 12., '', 'e211', 211, 'um', 1., 0., 0., 1., 211, 0, 0, 500, 250, 1) + (0, 16., 2120., 'square', 12., '', 'e212', 212, 'um', 1., 0., 0., 1., 212, 0, 0, 500, 250, 1) + (0, 48., 2120., 'square', 12., '', 'e213', 213, 'um', 1., 0., 0., 1., 213, 0, 0, 500, 250, 1) + (0, 0., 2140., 'square', 12., '', 'e214', 214, 'um', 1., 0., 0., 1., 214, 0, 0, 500, 250, 1) + (0, 32., 2140., 'square', 12., '', 'e215', 215, 'um', 1., 0., 0., 1., 215, 0, 0, 500, 250, 1) + (0, 16., 2160., 'square', 12., '', 'e216', 216, 'um', 1., 0., 0., 1., 216, 0, 0, 500, 250, 1) + (0, 48., 2160., 'square', 12., '', 'e217', 217, 'um', 1., 0., 0., 1., 217, 0, 0, 500, 250, 1) + (0, 0., 2180., 'square', 12., '', 'e218', 218, 'um', 1., 0., 0., 1., 218, 0, 0, 500, 250, 1) + (0, 32., 2180., 'square', 12., '', 'e219', 219, 'um', 1., 0., 0., 1., 219, 0, 0, 500, 250, 1) + (0, 16., 2200., 'square', 12., '', 'e220', 220, 'um', 1., 0., 0., 1., 220, 0, 0, 500, 250, 1) + (0, 48., 2200., 'square', 12., '', 'e221', 221, 'um', 1., 0., 0., 1., 221, 0, 0, 500, 250, 1) + (0, 0., 2220., 'square', 12., '', 'e222', 222, 'um', 1., 0., 0., 1., 222, 0, 0, 500, 250, 1) + (0, 32., 2220., 'square', 12., '', 'e223', 223, 'um', 1., 0., 0., 1., 223, 0, 0, 500, 250, 1) + (0, 16., 2240., 'square', 12., '', 'e224', 224, 'um', 1., 0., 0., 1., 224, 0, 0, 500, 250, 1) + (0, 48., 2240., 'square', 12., '', 'e225', 225, 'um', 1., 0., 0., 1., 225, 0, 0, 500, 250, 1) + (0, 0., 2260., 'square', 12., '', 'e226', 226, 'um', 1., 0., 0., 1., 226, 0, 0, 500, 250, 1) + (0, 32., 2260., 'square', 12., '', 'e227', 227, 'um', 1., 0., 0., 1., 227, 0, 0, 500, 250, 1) + (0, 16., 2280., 'square', 12., '', 'e228', 228, 'um', 1., 0., 0., 1., 228, 0, 0, 500, 250, 1) + (0, 48., 2280., 'square', 12., '', 'e229', 229, 'um', 1., 0., 0., 1., 229, 0, 0, 500, 250, 1) + (0, 0., 2300., 'square', 12., '', 'e230', 230, 'um', 1., 0., 0., 1., 230, 0, 0, 500, 250, 1) + (0, 32., 2300., 'square', 12., '', 'e231', 231, 'um', 1., 0., 0., 1., 231, 0, 0, 500, 250, 1) + (0, 16., 2320., 'square', 12., '', 'e232', 232, 'um', 1., 0., 0., 1., 232, 0, 0, 500, 250, 1) + (0, 48., 2320., 'square', 12., '', 'e233', 233, 'um', 1., 0., 0., 1., 233, 0, 0, 500, 250, 1) + (0, 0., 2340., 'square', 12., '', 'e234', 234, 'um', 1., 0., 0., 1., 234, 0, 0, 500, 250, 1) + (0, 32., 2340., 'square', 12., '', 'e235', 235, 'um', 1., 0., 0., 1., 235, 0, 0, 500, 250, 1) + (0, 16., 2360., 'square', 12., '', 'e236', 236, 'um', 1., 0., 0., 1., 236, 0, 0, 500, 250, 1) + (0, 48., 2360., 'square', 12., '', 'e237', 237, 'um', 1., 0., 0., 1., 237, 0, 0, 500, 250, 1) + (0, 0., 2380., 'square', 12., '', 'e238', 238, 'um', 1., 0., 0., 1., 238, 0, 0, 500, 250, 1) + (0, 32., 2380., 'square', 12., '', 'e239', 239, 'um', 1., 0., 0., 1., 239, 0, 0, 500, 250, 1) + (0, 16., 2400., 'square', 12., '', 'e240', 240, 'um', 1., 0., 0., 1., 240, 0, 0, 500, 250, 1) + (0, 48., 2400., 'square', 12., '', 'e241', 241, 'um', 1., 0., 0., 1., 241, 0, 0, 500, 250, 1) + (0, 0., 2420., 'square', 12., '', 'e242', 242, 'um', 1., 0., 0., 1., 242, 0, 0, 500, 250, 1) + (0, 32., 2420., 'square', 12., '', 'e243', 243, 'um', 1., 0., 0., 1., 243, 0, 0, 500, 250, 1) + (0, 16., 2440., 'square', 12., '', 'e244', 244, 'um', 1., 0., 0., 1., 244, 0, 0, 500, 250, 1) + (0, 48., 2440., 'square', 12., '', 'e245', 245, 'um', 1., 0., 0., 1., 245, 0, 0, 500, 250, 1) + (0, 0., 2460., 'square', 12., '', 'e246', 246, 'um', 1., 0., 0., 1., 246, 0, 0, 500, 250, 1) + (0, 32., 2460., 'square', 12., '', 'e247', 247, 'um', 1., 0., 0., 1., 247, 0, 0, 500, 250, 1) + (0, 16., 2480., 'square', 12., '', 'e248', 248, 'um', 1., 0., 0., 1., 248, 0, 0, 500, 250, 1) + (0, 48., 2480., 'square', 12., '', 'e249', 249, 'um', 1., 0., 0., 1., 249, 0, 0, 500, 250, 1) + (0, 0., 2500., 'square', 12., '', 'e250', 250, 'um', 1., 0., 0., 1., 250, 0, 0, 500, 250, 1) + (0, 32., 2500., 'square', 12., '', 'e251', 251, 'um', 1., 0., 0., 1., 251, 0, 0, 500, 250, 1) + (0, 16., 2520., 'square', 12., '', 'e252', 252, 'um', 1., 0., 0., 1., 252, 0, 0, 500, 250, 1) + (0, 48., 2520., 'square', 12., '', 'e253', 253, 'um', 1., 0., 0., 1., 253, 0, 0, 500, 250, 1) + (0, 0., 2540., 'square', 12., '', 'e254', 254, 'um', 1., 0., 0., 1., 254, 0, 0, 500, 250, 1) + (0, 32., 2540., 'square', 12., '', 'e255', 255, 'um', 1., 0., 0., 1., 255, 0, 0, 500, 250, 1) + (0, 16., 2560., 'square', 12., '', 'e256', 256, 'um', 1., 0., 0., 1., 256, 0, 0, 500, 250, 1) + (0, 48., 2560., 'square', 12., '', 'e257', 257, 'um', 1., 0., 0., 1., 257, 0, 0, 500, 250, 1) + (0, 0., 2580., 'square', 12., '', 'e258', 258, 'um', 1., 0., 0., 1., 258, 0, 0, 500, 250, 1) + (0, 32., 2580., 'square', 12., '', 'e259', 259, 'um', 1., 0., 0., 1., 259, 0, 0, 500, 250, 1) + (0, 16., 2600., 'square', 12., '', 'e260', 260, 'um', 1., 0., 0., 1., 260, 0, 0, 500, 250, 1) + (0, 48., 2600., 'square', 12., '', 'e261', 261, 'um', 1., 0., 0., 1., 261, 0, 0, 500, 250, 1) + (0, 0., 2620., 'square', 12., '', 'e262', 262, 'um', 1., 0., 0., 1., 262, 0, 0, 500, 250, 1) + (0, 32., 2620., 'square', 12., '', 'e263', 263, 'um', 1., 0., 0., 1., 263, 0, 0, 500, 250, 1) + (0, 16., 2640., 'square', 12., '', 'e264', 264, 'um', 1., 0., 0., 1., 264, 0, 0, 500, 250, 1) + (0, 48., 2640., 'square', 12., '', 'e265', 265, 'um', 1., 0., 0., 1., 265, 0, 0, 500, 250, 1) + (0, 0., 2660., 'square', 12., '', 'e266', 266, 'um', 1., 0., 0., 1., 266, 0, 0, 500, 250, 1) + (0, 32., 2660., 'square', 12., '', 'e267', 267, 'um', 1., 0., 0., 1., 267, 0, 0, 500, 250, 1) + (0, 16., 2680., 'square', 12., '', 'e268', 268, 'um', 1., 0., 0., 1., 268, 0, 0, 500, 250, 1) + (0, 48., 2680., 'square', 12., '', 'e269', 269, 'um', 1., 0., 0., 1., 269, 0, 0, 500, 250, 1) + (0, 0., 2700., 'square', 12., '', 'e270', 270, 'um', 1., 0., 0., 1., 270, 0, 0, 500, 250, 1) + (0, 32., 2700., 'square', 12., '', 'e271', 271, 'um', 1., 0., 0., 1., 271, 0, 0, 500, 250, 1) + (0, 16., 2720., 'square', 12., '', 'e272', 272, 'um', 1., 0., 0., 1., 272, 0, 0, 500, 250, 1) + (0, 48., 2720., 'square', 12., '', 'e273', 273, 'um', 1., 0., 0., 1., 273, 0, 0, 500, 250, 1) + (0, 0., 2740., 'square', 12., '', 'e274', 274, 'um', 1., 0., 0., 1., 274, 0, 0, 500, 250, 1) + (0, 32., 2740., 'square', 12., '', 'e275', 275, 'um', 1., 0., 0., 1., 275, 0, 0, 500, 250, 1) + (0, 16., 2760., 'square', 12., '', 'e276', 276, 'um', 1., 0., 0., 1., 276, 0, 0, 500, 250, 1) + (0, 48., 2760., 'square', 12., '', 'e277', 277, 'um', 1., 0., 0., 1., 277, 0, 0, 500, 250, 1) + (0, 0., 2780., 'square', 12., '', 'e278', 278, 'um', 1., 0., 0., 1., 278, 0, 0, 500, 250, 1) + (0, 32., 2780., 'square', 12., '', 'e279', 279, 'um', 1., 0., 0., 1., 279, 0, 0, 500, 250, 1) + (0, 16., 2800., 'square', 12., '', 'e280', 280, 'um', 1., 0., 0., 1., 280, 0, 0, 500, 250, 1) + (0, 48., 2800., 'square', 12., '', 'e281', 281, 'um', 1., 0., 0., 1., 281, 0, 0, 500, 250, 1) + (0, 0., 2820., 'square', 12., '', 'e282', 282, 'um', 1., 0., 0., 1., 282, 0, 0, 500, 250, 1) + (0, 32., 2820., 'square', 12., '', 'e283', 283, 'um', 1., 0., 0., 1., 283, 0, 0, 500, 250, 1) + (0, 16., 2840., 'square', 12., '', 'e284', 284, 'um', 1., 0., 0., 1., 284, 0, 0, 500, 250, 1) + (0, 48., 2840., 'square', 12., '', 'e285', 285, 'um', 1., 0., 0., 1., 285, 0, 0, 500, 250, 1) + (0, 0., 2860., 'square', 12., '', 'e286', 286, 'um', 1., 0., 0., 1., 286, 0, 0, 500, 250, 1) + (0, 32., 2860., 'square', 12., '', 'e287', 287, 'um', 1., 0., 0., 1., 287, 0, 0, 500, 250, 1) + (0, 16., 2880., 'square', 12., '', 'e288', 288, 'um', 1., 0., 0., 1., 288, 0, 0, 500, 250, 1) + (0, 48., 2880., 'square', 12., '', 'e289', 289, 'um', 1., 0., 0., 1., 289, 0, 0, 500, 250, 1) + (0, 0., 2900., 'square', 12., '', 'e290', 290, 'um', 1., 0., 0., 1., 290, 0, 0, 500, 250, 1) + (0, 32., 2900., 'square', 12., '', 'e291', 291, 'um', 1., 0., 0., 1., 291, 0, 0, 500, 250, 1) + (0, 16., 2920., 'square', 12., '', 'e292', 292, 'um', 1., 0., 0., 1., 292, 0, 0, 500, 250, 1) + (0, 48., 2920., 'square', 12., '', 'e293', 293, 'um', 1., 0., 0., 1., 293, 0, 0, 500, 250, 1) + (0, 0., 2940., 'square', 12., '', 'e294', 294, 'um', 1., 0., 0., 1., 294, 0, 0, 500, 250, 1) + (0, 32., 2940., 'square', 12., '', 'e295', 295, 'um', 1., 0., 0., 1., 295, 0, 0, 500, 250, 1) + (0, 16., 2960., 'square', 12., '', 'e296', 296, 'um', 1., 0., 0., 1., 296, 0, 0, 500, 250, 1) + (0, 48., 2960., 'square', 12., '', 'e297', 297, 'um', 1., 0., 0., 1., 297, 0, 0, 500, 250, 1) + (0, 0., 2980., 'square', 12., '', 'e298', 298, 'um', 1., 0., 0., 1., 298, 0, 0, 500, 250, 1) + (0, 32., 2980., 'square', 12., '', 'e299', 299, 'um', 1., 0., 0., 1., 299, 0, 0, 500, 250, 1) + (0, 16., 3000., 'square', 12., '', 'e300', 300, 'um', 1., 0., 0., 1., 300, 0, 0, 500, 250, 1) + (0, 48., 3000., 'square', 12., '', 'e301', 301, 'um', 1., 0., 0., 1., 301, 0, 0, 500, 250, 1) + (0, 0., 3020., 'square', 12., '', 'e302', 302, 'um', 1., 0., 0., 1., 302, 0, 0, 500, 250, 1) + (0, 32., 3020., 'square', 12., '', 'e303', 303, 'um', 1., 0., 0., 1., 303, 0, 0, 500, 250, 1) + (0, 16., 3040., 'square', 12., '', 'e304', 304, 'um', 1., 0., 0., 1., 304, 0, 0, 500, 250, 1) + (0, 48., 3040., 'square', 12., '', 'e305', 305, 'um', 1., 0., 0., 1., 305, 0, 0, 500, 250, 1) + (0, 0., 3060., 'square', 12., '', 'e306', 306, 'um', 1., 0., 0., 1., 306, 0, 0, 500, 250, 1) + (0, 32., 3060., 'square', 12., '', 'e307', 307, 'um', 1., 0., 0., 1., 307, 0, 0, 500, 250, 1) + (0, 16., 3080., 'square', 12., '', 'e308', 308, 'um', 1., 0., 0., 1., 308, 0, 0, 500, 250, 1) + (0, 48., 3080., 'square', 12., '', 'e309', 309, 'um', 1., 0., 0., 1., 309, 0, 0, 500, 250, 1) + (0, 0., 3100., 'square', 12., '', 'e310', 310, 'um', 1., 0., 0., 1., 310, 0, 0, 500, 250, 1) + (0, 32., 3100., 'square', 12., '', 'e311', 311, 'um', 1., 0., 0., 1., 311, 0, 0, 500, 250, 1) + (0, 16., 3120., 'square', 12., '', 'e312', 312, 'um', 1., 0., 0., 1., 312, 0, 0, 500, 250, 1) + (0, 48., 3120., 'square', 12., '', 'e313', 313, 'um', 1., 0., 0., 1., 313, 0, 0, 500, 250, 1) + (0, 0., 3140., 'square', 12., '', 'e314', 314, 'um', 1., 0., 0., 1., 314, 0, 0, 500, 250, 1) + (0, 32., 3140., 'square', 12., '', 'e315', 315, 'um', 1., 0., 0., 1., 315, 0, 0, 500, 250, 1) + (0, 16., 3160., 'square', 12., '', 'e316', 316, 'um', 1., 0., 0., 1., 316, 0, 0, 500, 250, 1) + (0, 48., 3160., 'square', 12., '', 'e317', 317, 'um', 1., 0., 0., 1., 317, 0, 0, 500, 250, 1) + (0, 0., 3180., 'square', 12., '', 'e318', 318, 'um', 1., 0., 0., 1., 318, 0, 0, 500, 250, 1) + (0, 32., 3180., 'square', 12., '', 'e319', 319, 'um', 1., 0., 0., 1., 319, 0, 0, 500, 250, 1) + (0, 16., 3200., 'square', 12., '', 'e320', 320, 'um', 1., 0., 0., 1., 320, 0, 0, 500, 250, 1) + (0, 48., 3200., 'square', 12., '', 'e321', 321, 'um', 1., 0., 0., 1., 321, 0, 0, 500, 250, 1) + (0, 0., 3220., 'square', 12., '', 'e322', 322, 'um', 1., 0., 0., 1., 322, 0, 0, 500, 250, 1) + (0, 32., 3220., 'square', 12., '', 'e323', 323, 'um', 1., 0., 0., 1., 323, 0, 0, 500, 250, 1) + (0, 16., 3240., 'square', 12., '', 'e324', 324, 'um', 1., 0., 0., 1., 324, 0, 0, 500, 250, 1) + (0, 48., 3240., 'square', 12., '', 'e325', 325, 'um', 1., 0., 0., 1., 325, 0, 0, 500, 250, 1) + (0, 0., 3260., 'square', 12., '', 'e326', 326, 'um', 1., 0., 0., 1., 326, 0, 0, 500, 250, 1) + (0, 32., 3260., 'square', 12., '', 'e327', 327, 'um', 1., 0., 0., 1., 327, 0, 0, 500, 250, 1) + (0, 16., 3280., 'square', 12., '', 'e328', 328, 'um', 1., 0., 0., 1., 328, 0, 0, 500, 250, 1) + (0, 48., 3280., 'square', 12., '', 'e329', 329, 'um', 1., 0., 0., 1., 329, 0, 0, 500, 250, 1) + (0, 0., 3300., 'square', 12., '', 'e330', 330, 'um', 1., 0., 0., 1., 330, 0, 0, 500, 250, 1) + (0, 32., 3300., 'square', 12., '', 'e331', 331, 'um', 1., 0., 0., 1., 331, 0, 0, 500, 250, 1) + (0, 16., 3320., 'square', 12., '', 'e332', 332, 'um', 1., 0., 0., 1., 332, 0, 0, 500, 250, 1) + (0, 48., 3320., 'square', 12., '', 'e333', 333, 'um', 1., 0., 0., 1., 333, 0, 0, 500, 250, 1) + (0, 0., 3340., 'square', 12., '', 'e334', 334, 'um', 1., 0., 0., 1., 334, 0, 0, 500, 250, 1) + (0, 32., 3340., 'square', 12., '', 'e335', 335, 'um', 1., 0., 0., 1., 335, 0, 0, 500, 250, 1) + (0, 16., 3360., 'square', 12., '', 'e336', 336, 'um', 1., 0., 0., 1., 336, 0, 0, 500, 250, 1) + (0, 48., 3360., 'square', 12., '', 'e337', 337, 'um', 1., 0., 0., 1., 337, 0, 0, 500, 250, 1) + (0, 0., 3380., 'square', 12., '', 'e338', 338, 'um', 1., 0., 0., 1., 338, 0, 0, 500, 250, 1) + (0, 32., 3380., 'square', 12., '', 'e339', 339, 'um', 1., 0., 0., 1., 339, 0, 0, 500, 250, 1) + (0, 16., 3400., 'square', 12., '', 'e340', 340, 'um', 1., 0., 0., 1., 340, 0, 0, 500, 250, 1) + (0, 48., 3400., 'square', 12., '', 'e341', 341, 'um', 1., 0., 0., 1., 341, 0, 0, 500, 250, 1) + (0, 0., 3420., 'square', 12., '', 'e342', 342, 'um', 1., 0., 0., 1., 342, 0, 0, 500, 250, 1) + (0, 32., 3420., 'square', 12., '', 'e343', 343, 'um', 1., 0., 0., 1., 343, 0, 0, 500, 250, 1) + (0, 16., 3440., 'square', 12., '', 'e344', 344, 'um', 1., 0., 0., 1., 344, 0, 0, 500, 250, 1) + (0, 48., 3440., 'square', 12., '', 'e345', 345, 'um', 1., 0., 0., 1., 345, 0, 0, 500, 250, 1) + (0, 0., 3460., 'square', 12., '', 'e346', 346, 'um', 1., 0., 0., 1., 346, 0, 0, 500, 250, 1) + (0, 32., 3460., 'square', 12., '', 'e347', 347, 'um', 1., 0., 0., 1., 347, 0, 0, 500, 250, 1) + (0, 16., 3480., 'square', 12., '', 'e348', 348, 'um', 1., 0., 0., 1., 348, 0, 0, 500, 250, 1) + (0, 48., 3480., 'square', 12., '', 'e349', 349, 'um', 1., 0., 0., 1., 349, 0, 0, 500, 250, 1) + (0, 0., 3500., 'square', 12., '', 'e350', 350, 'um', 1., 0., 0., 1., 350, 0, 0, 500, 250, 1) + (0, 32., 3500., 'square', 12., '', 'e351', 351, 'um', 1., 0., 0., 1., 351, 0, 0, 500, 250, 1) + (0, 16., 3520., 'square', 12., '', 'e352', 352, 'um', 1., 0., 0., 1., 352, 0, 0, 500, 250, 1) + (0, 48., 3520., 'square', 12., '', 'e353', 353, 'um', 1., 0., 0., 1., 353, 0, 0, 500, 250, 1) + (0, 0., 3540., 'square', 12., '', 'e354', 354, 'um', 1., 0., 0., 1., 354, 0, 0, 500, 250, 1) + (0, 32., 3540., 'square', 12., '', 'e355', 355, 'um', 1., 0., 0., 1., 355, 0, 0, 500, 250, 1) + (0, 16., 3560., 'square', 12., '', 'e356', 356, 'um', 1., 0., 0., 1., 356, 0, 0, 500, 250, 1) + (0, 48., 3560., 'square', 12., '', 'e357', 357, 'um', 1., 0., 0., 1., 357, 0, 0, 500, 250, 1) + (0, 0., 3580., 'square', 12., '', 'e358', 358, 'um', 1., 0., 0., 1., 358, 0, 0, 500, 250, 1) + (0, 32., 3580., 'square', 12., '', 'e359', 359, 'um', 1., 0., 0., 1., 359, 0, 0, 500, 250, 1) + (0, 16., 3600., 'square', 12., '', 'e360', 360, 'um', 1., 0., 0., 1., 360, 0, 0, 500, 250, 1) + (0, 48., 3600., 'square', 12., '', 'e361', 361, 'um', 1., 0., 0., 1., 361, 0, 0, 500, 250, 1) + (0, 0., 3620., 'square', 12., '', 'e362', 362, 'um', 1., 0., 0., 1., 362, 0, 0, 500, 250, 1) + (0, 32., 3620., 'square', 12., '', 'e363', 363, 'um', 1., 0., 0., 1., 363, 0, 0, 500, 250, 1) + (0, 16., 3640., 'square', 12., '', 'e364', 364, 'um', 1., 0., 0., 1., 364, 0, 0, 500, 250, 1) + (0, 48., 3640., 'square', 12., '', 'e365', 365, 'um', 1., 0., 0., 1., 365, 0, 0, 500, 250, 1) + (0, 0., 3660., 'square', 12., '', 'e366', 366, 'um', 1., 0., 0., 1., 366, 0, 0, 500, 250, 1) + (0, 32., 3660., 'square', 12., '', 'e367', 367, 'um', 1., 0., 0., 1., 367, 0, 0, 500, 250, 1) + (0, 16., 3680., 'square', 12., '', 'e368', 368, 'um', 1., 0., 0., 1., 368, 0, 0, 500, 250, 1) + (0, 48., 3680., 'square', 12., '', 'e369', 369, 'um', 1., 0., 0., 1., 369, 0, 0, 500, 250, 1) + (0, 0., 3700., 'square', 12., '', 'e370', 370, 'um', 1., 0., 0., 1., 370, 0, 0, 500, 250, 1) + (0, 32., 3700., 'square', 12., '', 'e371', 371, 'um', 1., 0., 0., 1., 371, 0, 0, 500, 250, 1) + (0, 16., 3720., 'square', 12., '', 'e372', 372, 'um', 1., 0., 0., 1., 372, 0, 0, 500, 250, 1) + (0, 48., 3720., 'square', 12., '', 'e373', 373, 'um', 1., 0., 0., 1., 373, 0, 0, 500, 250, 1) + (0, 0., 3740., 'square', 12., '', 'e374', 374, 'um', 1., 0., 0., 1., 374, 0, 0, 500, 250, 1) + (0, 32., 3740., 'square', 12., '', 'e375', 375, 'um', 1., 0., 0., 1., 375, 0, 0, 500, 250, 1) + (0, 16., 3760., 'square', 12., '', 'e376', 376, 'um', 1., 0., 0., 1., 376, 0, 0, 500, 250, 1) + (0, 48., 3760., 'square', 12., '', 'e377', 377, 'um', 1., 0., 0., 1., 377, 0, 0, 500, 250, 1) + (0, 0., 3780., 'square', 12., '', 'e378', 378, 'um', 1., 0., 0., 1., 378, 0, 0, 500, 250, 1) + (0, 32., 3780., 'square', 12., '', 'e379', 379, 'um', 1., 0., 0., 1., 379, 0, 0, 500, 250, 1) + (0, 16., 3800., 'square', 12., '', 'e380', 380, 'um', 1., 0., 0., 1., 380, 0, 0, 500, 250, 1) + (0, 48., 3800., 'square', 12., '', 'e381', 381, 'um', 1., 0., 0., 1., 381, 0, 0, 500, 250, 1) + (0, 0., 3820., 'square', 12., '', 'e382', 382, 'um', 1., 0., 0., 1., 382, 0, 0, 500, 250, 1) + (0, 32., 3820., 'square', 12., '', 'e383', 383, 'um', 1., 0., 0., 1., 383, 0, 0, 500, 250, 1)]
    location [[ 16. 0.] + [ 48. 0.] + [ 0. 20.] + [ 32. 20.] + [ 16. 40.] + [ 48. 40.] + [ 0. 60.] + [ 32. 60.] + [ 16. 80.] + [ 48. 80.] + [ 0. 100.] + [ 32. 100.] + [ 16. 120.] + [ 48. 120.] + [ 0. 140.] + [ 32. 140.] + [ 16. 160.] + [ 48. 160.] + [ 0. 180.] + [ 32. 180.] + [ 16. 200.] + [ 48. 200.] + [ 0. 220.] + [ 32. 220.] + [ 16. 240.] + [ 48. 240.] + [ 0. 260.] + [ 32. 260.] + [ 16. 280.] + [ 48. 280.] + [ 0. 300.] + [ 32. 300.] + [ 16. 320.] + [ 48. 320.] + [ 0. 340.] + [ 32. 340.] + [ 16. 360.] + [ 48. 360.] + [ 0. 380.] + [ 32. 380.] + [ 16. 400.] + [ 48. 400.] + [ 0. 420.] + [ 32. 420.] + [ 16. 440.] + [ 48. 440.] + [ 0. 460.] + [ 32. 460.] + [ 16. 480.] + [ 48. 480.] + [ 0. 500.] + [ 32. 500.] + [ 16. 520.] + [ 48. 520.] + [ 0. 540.] + [ 32. 540.] + [ 16. 560.] + [ 48. 560.] + [ 0. 580.] + [ 32. 580.] + [ 16. 600.] + [ 48. 600.] + [ 0. 620.] + [ 32. 620.] + [ 16. 640.] + [ 48. 640.] + [ 0. 660.] + [ 32. 660.] + [ 16. 680.] + [ 48. 680.] + [ 0. 700.] + [ 32. 700.] + [ 16. 720.] + [ 48. 720.] + [ 0. 740.] + [ 32. 740.] + [ 16. 760.] + [ 48. 760.] + [ 0. 780.] + [ 32. 780.] + [ 16. 800.] + [ 48. 800.] + [ 0. 820.] + [ 32. 820.] + [ 16. 840.] + [ 48. 840.] + [ 0. 860.] + [ 32. 860.] + [ 16. 880.] + [ 48. 880.] + [ 0. 900.] + [ 32. 900.] + [ 16. 920.] + [ 48. 920.] + [ 0. 940.] + [ 32. 940.] + [ 16. 960.] + [ 48. 960.] + [ 0. 980.] + [ 32. 980.] + [ 16. 1000.] + [ 48. 1000.] + [ 0. 1020.] + [ 32. 1020.] + [ 16. 1040.] + [ 48. 1040.] + [ 0. 1060.] + [ 32. 1060.] + [ 16. 1080.] + [ 48. 1080.] + [ 0. 1100.] + [ 32. 1100.] + [ 16. 1120.] + [ 48. 1120.] + [ 0. 1140.] + [ 32. 1140.] + [ 16. 1160.] + [ 48. 1160.] + [ 0. 1180.] + [ 32. 1180.] + [ 16. 1200.] + [ 48. 1200.] + [ 0. 1220.] + [ 32. 1220.] + [ 16. 1240.] + [ 48. 1240.] + [ 0. 1260.] + [ 32. 1260.] + [ 16. 1280.] + [ 48. 1280.] + [ 0. 1300.] + [ 32. 1300.] + [ 16. 1320.] + [ 48. 1320.] + [ 0. 1340.] + [ 32. 1340.] + [ 16. 1360.] + [ 48. 1360.] + [ 0. 1380.] + [ 32. 1380.] + [ 16. 1400.] + [ 48. 1400.] + [ 0. 1420.] + [ 32. 1420.] + [ 16. 1440.] + [ 48. 1440.] + [ 0. 1460.] + [ 32. 1460.] + [ 16. 1480.] + [ 48. 1480.] + [ 0. 1500.] + [ 32. 1500.] + [ 16. 1520.] + [ 48. 1520.] + [ 0. 1540.] + [ 32. 1540.] + [ 16. 1560.] + [ 48. 1560.] + [ 0. 1580.] + [ 32. 1580.] + [ 16. 1600.] + [ 48. 1600.] + [ 0. 1620.] + [ 32. 1620.] + [ 16. 1640.] + [ 48. 1640.] + [ 0. 1660.] + [ 32. 1660.] + [ 16. 1680.] + [ 48. 1680.] + [ 0. 1700.] + [ 32. 1700.] + [ 16. 1720.] + [ 48. 1720.] + [ 0. 1740.] + [ 32. 1740.] + [ 16. 1760.] + [ 48. 1760.] + [ 0. 1780.] + [ 32. 1780.] + [ 16. 1800.] + [ 48. 1800.] + [ 0. 1820.] + [ 32. 1820.] + [ 16. 1840.] + [ 48. 1840.] + [ 0. 1860.] + [ 32. 1860.] + [ 16. 1880.] + [ 48. 1880.] + [ 0. 1900.] + [ 32. 1900.] + [ 16. 1920.] + [ 48. 1920.] + [ 0. 1940.] + [ 32. 1940.] + [ 16. 1960.] + [ 48. 1960.] + [ 0. 1980.] + [ 32. 1980.] + [ 16. 2000.] + [ 48. 2000.] + [ 0. 2020.] + [ 32. 2020.] + [ 16. 2040.] + [ 48. 2040.] + [ 0. 2060.] + [ 32. 2060.] + [ 16. 2080.] + [ 48. 2080.] + [ 0. 2100.] + [ 32. 2100.] + [ 16. 2120.] + [ 48. 2120.] + [ 0. 2140.] + [ 32. 2140.] + [ 16. 2160.] + [ 48. 2160.] + [ 0. 2180.] + [ 32. 2180.] + [ 16. 2200.] + [ 48. 2200.] + [ 0. 2220.] + [ 32. 2220.] + [ 16. 2240.] + [ 48. 2240.] + [ 0. 2260.] + [ 32. 2260.] + [ 16. 2280.] + [ 48. 2280.] + [ 0. 2300.] + [ 32. 2300.] + [ 16. 2320.] + [ 48. 2320.] + [ 0. 2340.] + [ 32. 2340.] + [ 16. 2360.] + [ 48. 2360.] + [ 0. 2380.] + [ 32. 2380.] + [ 16. 2400.] + [ 48. 2400.] + [ 0. 2420.] + [ 32. 2420.] + [ 16. 2440.] + [ 48. 2440.] + [ 0. 2460.] + [ 32. 2460.] + [ 16. 2480.] + [ 48. 2480.] + [ 0. 2500.] + [ 32. 2500.] + [ 16. 2520.] + [ 48. 2520.] + [ 0. 2540.] + [ 32. 2540.] + [ 16. 2560.] + [ 48. 2560.] + [ 0. 2580.] + [ 32. 2580.] + [ 16. 2600.] + [ 48. 2600.] + [ 0. 2620.] + [ 32. 2620.] + [ 16. 2640.] + [ 48. 2640.] + [ 0. 2660.] + [ 32. 2660.] + [ 16. 2680.] + [ 48. 2680.] + [ 0. 2700.] + [ 32. 2700.] + [ 16. 2720.] + [ 48. 2720.] + [ 0. 2740.] + [ 32. 2740.] + [ 16. 2760.] + [ 48. 2760.] + [ 0. 2780.] + [ 32. 2780.] + [ 16. 2800.] + [ 48. 2800.] + [ 0. 2820.] + [ 32. 2820.] + [ 16. 2840.] + [ 48. 2840.] + [ 0. 2860.] + [ 32. 2860.] + [ 16. 2880.] + [ 48. 2880.] + [ 0. 2900.] + [ 32. 2900.] + [ 16. 2920.] + [ 48. 2920.] + [ 0. 2940.] + [ 32. 2940.] + [ 16. 2960.] + [ 48. 2960.] + [ 0. 2980.] + [ 32. 2980.] + [ 16. 3000.] + [ 48. 3000.] + [ 0. 3020.] + [ 32. 3020.] + [ 16. 3040.] + [ 48. 3040.] + [ 0. 3060.] + [ 32. 3060.] + [ 16. 3080.] + [ 48. 3080.] + [ 0. 3100.] + [ 32. 3100.] + [ 16. 3120.] + [ 48. 3120.] + [ 0. 3140.] + [ 32. 3140.] + [ 16. 3160.] + [ 48. 3160.] + [ 0. 3180.] + [ 32. 3180.] + [ 16. 3200.] + [ 48. 3200.] + [ 0. 3220.] + [ 32. 3220.] + [ 16. 3240.] + [ 48. 3240.] + [ 0. 3260.] + [ 32. 3260.] + [ 16. 3280.] + [ 48. 3280.] + [ 0. 3300.] + [ 32. 3300.] + [ 16. 3320.] + [ 48. 3320.] + [ 0. 3340.] + [ 32. 3340.] + [ 16. 3360.] + [ 48. 3360.] + [ 0. 3380.] + [ 32. 3380.] + [ 16. 3400.] + [ 48. 3400.] + [ 0. 3420.] + [ 32. 3420.] + [ 16. 3440.] + [ 48. 3440.] + [ 0. 3460.] + [ 32. 3460.] + [ 16. 3480.] + [ 48. 3480.] + [ 0. 3500.] + [ 32. 3500.] + [ 16. 3520.] + [ 48. 3520.] + [ 0. 3540.] + [ 32. 3540.] + [ 16. 3560.] + [ 48. 3560.] + [ 0. 3580.] + [ 32. 3580.] + [ 16. 3600.] + [ 48. 3600.] + [ 0. 3620.] + [ 32. 3620.] + [ 16. 3640.] + [ 48. 3640.] + [ 0. 3660.] + [ 32. 3660.] + [ 16. 3680.] + [ 48. 3680.] + [ 0. 3700.] + [ 32. 3700.] + [ 16. 3720.] + [ 48. 3720.] + [ 0. 3740.] + [ 32. 3740.] + [ 16. 3760.] + [ 48. 3760.] + [ 0. 3780.] + [ 32. 3780.] + [ 16. 3800.] + [ 48. 3800.] + [ 0. 3820.] + [ 32. 3820.]]
    group [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
    inter_sample_shift [0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385 + 0. 0. 0.07692308 0.07692308 0.15384615 0.15384615 + 0.23076923 0.23076923 0.30769231 0.30769231 0.38461538 0.38461538 + 0.46153846 0.46153846 0.53846154 0.53846154 0.61538462 0.61538462 + 0.69230769 0.69230769 0.76923077 0.76923077 0.84615385 0.84615385]
@@ -77,89 +1115,245 @@ We preprocess the recording with bandpass filter and a common median reference. Note, that it is better to not whiten the recording before motion estimation to get a better estimate of peak locations! -.. code:: ipython +.. code:: ipython3 def preprocess_chain(rec): - rec = si.bandpass_filter(rec, freq_min=300., freq_max=6000.) - rec = si.common_reference(rec, reference='global', operator='median') + rec = rec.astype('float32') + rec = si.bandpass_filter(rec, freq_min=300.0, freq_max=6000.0) + rec = si.common_reference(rec, reference="global", operator="median") return rec - rec = preprocess_chain(raw_rec) -.. code:: ipython +.. code:: ipython3 - job_kwargs = dict(n_jobs=40, chunk_duration='1s', progress_bar=True) + rec = preprocess_chain(raw_rec) -Run motion correction with one function! -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code:: ipython3 + + job_kwargs = dict(n_jobs=40, chunk_duration="1s", progress_bar=True) Correcting for drift is easy! You just need to run a single function. We -will try this function with 3 presets. +will try this function with some presets. Internally a preset is a dictionary of dictionaries containing all -parameters for each step. +parameters for every steps. Here we also save the motion correction results into a folder to be able to load them later. -.. code:: ipython +preset and parameters +~~~~~~~~~~~~~~~~~~~~~ - # internally, we can explore a preset like this - # every parameter can be overwritten at runtime - from spikeinterface.preprocessing.motion import motion_options_preset - motion_options_preset['kilosort_like'] +Motion correction has some steps and eevry step can be controlled by a +method and related parameters. + +A preset is a nested dict that contains theses methods/parameters. + +.. code:: ipython3 + + preset_keys = get_motion_presets() + preset_keys .. parsed-literal:: - {'doc': 'Mimic the drift correction of kilosrt (grid_convolution + iterative_template)', - 'detect_kwargs': {'method': 'locally_exclusive', - 'peak_sign': 'neg', + ['dredge', + 'dredge_fast', + 'nonrigid_accurate', + 'nonrigid_fast_and_accurate', + 'rigid_fast', + 'kilosort_like'] + + + +.. code:: ipython3 + + one_preset_params = get_motion_parameters_preset("kilosort_like") + one_preset_params + + + + +.. parsed-literal:: + + {'doc': 'Mimic the drift correction of kilosort (grid_convolution + iterative_template)', + 'detect_kwargs': {'peak_sign': 'neg', 'detect_threshold': 8.0, 'exclude_sweep_ms': 0.1, - 'radius_um': 50}, - 'select_kwargs': None, - 'localize_peaks_kwargs': {'method': 'grid_convolution', - 'radius_um': 30.0, - 'upsampling_um': 3.0, - 'sigma_um': array([ 5. , 12.5, 20. ]), + 'radius_um': 50, + 'noise_levels': None, + 'random_chunk_kwargs': {}, + 'method': 'locally_exclusive'}, + 'select_kwargs': {}, + 'localize_peaks_kwargs': {'radius_um': 40.0, + 'upsampling_um': 5.0, 'sigma_ms': 0.25, - 'margin_um': 30.0, + 'margin_um': 50.0, 'prototype': None, - 'percentile': 5.0}, - 'estimate_motion_kwargs': {'method': 'iterative_template', - 'bin_duration_s': 2.0, + 'percentile': 5.0, + 'peak_sign': 'neg', + 'weight_method': {'mode': 'gaussian_2d', + 'sigma_list_um': array([ 5., 10., 15., 20., 25.])}, + 'method': 'grid_convolution'}, + 'estimate_motion_kwargs': {'direction': 'y', 'rigid': False, - 'win_step_um': 50.0, - 'win_sigma_um': 150.0, - 'margin_um': 0, - 'win_shape': 'rect'}, - 'interpolate_motion_kwargs': {'direction': 1, - 'border_mode': 'force_extrapolate', + 'win_shape': 'rect', + 'win_step_um': 200.0, + 'win_scale_um': 400.0, + 'win_margin_um': None, + 'bin_um': 10.0, + 'hist_margin_um': 0, + 'bin_s': 2.0, + 'num_amp_bins': 20, + 'num_shifts_global': 15, + 'num_iterations': 10, + 'num_shifts_block': 5, + 'smoothing_sigma': 0.5, + 'kriging_sigma': 1, + 'kriging_p': 2, + 'kriging_d': 2, + 'method': 'iterative_template'}, + 'interpolate_motion_kwargs': {'border_mode': 'force_extrapolate', 'spatial_interpolation_method': 'kriging', - 'sigma_um': [20.0, 30], - 'p': 1}} + 'sigma_um': 20.0, + 'p': 2}} + + + +Run motion correction with one function! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Correcting for drift is easy! You just need to run a single function. We +will try this function with some presets. +Here we also save the motion correction results into a folder to be able +to load them later. -.. code:: ipython +.. code:: ipython3 - # lets try theses 3 presets - some_presets = ('rigid_fast', 'kilosort_like', 'nonrigid_accurate') - # some_presets = ('nonrigid_accurate', ) + # lets try theses presets + some_presets = ("rigid_fast", "kilosort_like", "nonrigid_accurate", "nonrigid_fast_and_accurate", "dredge", "dredge_fast") -.. code:: ipython +.. code:: ipython3 - # compute motion with 3 presets + # compute motion with theses presets for preset in some_presets: - print('Computing with', preset) - folder = base_folder / 'motion_folder_dataset1' / preset + print("Computing with", preset) + folder = base_folder / "motion_folder_dataset1" / preset if folder.exists(): shutil.rmtree(folder) - recording_corrected, motion_info = si.correct_motion(rec, preset=preset, - folder=folder, - output_motion_info=True, **job_kwargs) + recording_corrected, motion, motion_info = si.correct_motion( + rec, preset=preset, folder=folder, output_motion=True, output_motion_info=True, **job_kwargs + ) + + +.. parsed-literal:: + + Computing with rigid_fast + + + +.. parsed-literal:: + + detect and localize: 0%| | 0/1958 [00:00 int(sr * time_lim0)) & (peaks['sample_index'] < int(sr * time_lim1)) + time_lim0 = 750.0 + time_lim1 = 1500.0 + mask = (peaks["sample_index"] > int(sr * time_lim0)) & (peaks["sample_index"] < int(sr * time_lim1)) sl = slice(None, None, 5) - amps = np.abs(peaks['amplitude'][mask][sl]) + amps = np.abs(peaks["amplitude"][mask][sl]) amps /= np.quantile(amps, 0.95) - c = plt.get_cmap('inferno')(amps) + c = plt.get_cmap("inferno")(amps) color_kargs = dict(alpha=0.2, s=2, c=c) - loc = motion_info['peak_locations'] - #color='black', - ax.scatter(loc['x'][mask][sl], loc['y'][mask][sl], **color_kargs) + peak_locations = motion_info["peak_locations"] + # color='black', + ax.scatter(peak_locations["x"][mask][sl], peak_locations["y"][mask][sl], **color_kargs) - loc2 = correct_motion_on_peaks(motion_info['peaks'], motion_info['peak_locations'], rec.sampling_frequency, - motion_info['motion'], motion_info['temporal_bins'], motion_info['spatial_bins'], direction="y") + peak_locations2 = correct_motion_on_peaks(peaks, peak_locations, motion,rec) ax = axs[1] si.plot_probe_map(rec, ax=ax) # color='black', - ax.scatter(loc2['x'][mask][sl], loc2['y'][mask][sl], **color_kargs) + ax.scatter(peak_locations2["x"][mask][sl], peak_locations2["y"][mask][sl], **color_kargs) ax.set_ylim(400, 600) fig.suptitle(f"{preset=}") @@ -286,15 +1506,27 @@ to display the results. -.. image:: handle_drift_files/handle_drift_15_0.png +.. image:: handle_drift_files/handle_drift_19_0.png + + +.. image:: handle_drift_files/handle_drift_19_1.png -.. image:: handle_drift_files/handle_drift_15_1.png +.. image:: handle_drift_files/handle_drift_19_2.png -.. image:: handle_drift_files/handle_drift_15_2.png + +.. image:: handle_drift_files/handle_drift_19_3.png + + + +.. image:: handle_drift_files/handle_drift_19_4.png + + + +.. image:: handle_drift_files/handle_drift_19_5.png run times @@ -303,20 +1535,20 @@ run times Presets and related methods have differents accuracies but also computation speeds. It is good to have this in mind! -.. code:: ipython +.. code:: ipython3 run_times = [] for preset in some_presets: - folder = base_folder / 'motion_folder_dataset1' / preset + folder = base_folder / "motion_folder_dataset1" / preset motion_info = si.load_motion_info(folder) - run_times.append(motion_info['run_times']) + run_times.append(motion_info["run_times"]) keys = run_times[0].keys() bottom = np.zeros(len(run_times)) - fig, ax = plt.subplots() + fig, ax = plt.subplots(figsize=(14, 6)) for k in keys: rtimes = np.array([rt[k] for rt in run_times]) - if np.any(rtimes>0.): + if np.any(rtimes > 0.0): ax.bar(some_presets, rtimes, bottom=bottom, label=k) bottom += rtimes ax.legend() @@ -326,9 +1558,9 @@ computation speeds. It is good to have this in mind! .. parsed-literal:: - + -.. image:: handle_drift_files/handle_drift_17_1.png +.. image:: handle_drift_files/handle_drift_21_1.png diff --git a/doc/how_to/handle_drift_files/handle_drift_13_0.png b/doc/how_to/handle_drift_files/handle_drift_13_0.png deleted file mode 100644 index 6bf7c0c882..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_13_0.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_13_1.png b/doc/how_to/handle_drift_files/handle_drift_13_1.png deleted file mode 100644 index 2474ff8f90..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_13_1.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_13_2.png b/doc/how_to/handle_drift_files/handle_drift_13_2.png deleted file mode 100644 index 2dacb64a6d..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_13_2.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_15_0.png b/doc/how_to/handle_drift_files/handle_drift_15_0.png deleted file mode 100644 index 60b2b076d0..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_15_0.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_15_1.png b/doc/how_to/handle_drift_files/handle_drift_15_1.png deleted file mode 100644 index 5581e25854..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_15_1.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_15_2.png b/doc/how_to/handle_drift_files/handle_drift_15_2.png deleted file mode 100644 index ada07c8c3c..0000000000 Binary files a/doc/how_to/handle_drift_files/handle_drift_15_2.png and /dev/null differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_0.png b/doc/how_to/handle_drift_files/handle_drift_17_0.png new file mode 100644 index 0000000000..e57d254767 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_17_0.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_1.png b/doc/how_to/handle_drift_files/handle_drift_17_1.png index b1a64b6345..2cd5a66e7c 100644 Binary files a/doc/how_to/handle_drift_files/handle_drift_17_1.png and b/doc/how_to/handle_drift_files/handle_drift_17_1.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_2.png b/doc/how_to/handle_drift_files/handle_drift_17_2.png new file mode 100644 index 0000000000..4cd4a71f8c Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_17_2.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_3.png b/doc/how_to/handle_drift_files/handle_drift_17_3.png new file mode 100644 index 0000000000..814db4178b Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_17_3.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_4.png b/doc/how_to/handle_drift_files/handle_drift_17_4.png new file mode 100644 index 0000000000..1a95dda15c Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_17_4.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_17_5.png b/doc/how_to/handle_drift_files/handle_drift_17_5.png new file mode 100644 index 0000000000..b1bbe234c8 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_17_5.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_0.png b/doc/how_to/handle_drift_files/handle_drift_19_0.png new file mode 100644 index 0000000000..969753e532 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_0.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_1.png b/doc/how_to/handle_drift_files/handle_drift_19_1.png new file mode 100644 index 0000000000..37eeea3655 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_1.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_2.png b/doc/how_to/handle_drift_files/handle_drift_19_2.png new file mode 100644 index 0000000000..eb593303a3 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_2.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_3.png b/doc/how_to/handle_drift_files/handle_drift_19_3.png new file mode 100644 index 0000000000..8917421d2c Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_3.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_4.png b/doc/how_to/handle_drift_files/handle_drift_19_4.png new file mode 100644 index 0000000000..5ffcddb092 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_4.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_19_5.png b/doc/how_to/handle_drift_files/handle_drift_19_5.png new file mode 100644 index 0000000000..0a200d3bd7 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_19_5.png differ diff --git a/doc/how_to/handle_drift_files/handle_drift_21_1.png b/doc/how_to/handle_drift_files/handle_drift_21_1.png new file mode 100644 index 0000000000..e8bd6b5ff1 Binary files /dev/null and b/doc/how_to/handle_drift_files/handle_drift_21_1.png differ diff --git a/doc/modules/curation.rst b/doc/modules/curation.rst index 8e5418b66e..d115b33e4a 100644 --- a/doc/modules/curation.rst +++ b/doc/modules/curation.rst @@ -261,11 +261,23 @@ format is the definition; the second part of the format is manual action): } -.. note:: - The curation format was recently introduced (v0.101.0), and we are still working on - properly integrating it into the SpikeInterface ecosystem. - Soon there will be functions vailable, in the curation module, to apply this - standardized curation format to ``SortingAnalyzer`` and a ``BaseSorting`` objects. +The curation format can be loaded into a dictionary and directly applied to +a ``BaseSorting`` or ``SortingAnalyzer`` object using the :py:func:`~spikeinterface.curation.apply_curation` function. + +.. code-block:: python + + from spikeinterface.curation import apply_curation + + # load the curation JSON file + curation_json = "path/to/curation.json" + with open(curation_json, 'r') as f: + curation_dict = json.load(f) + + # apply the curation to the sorting output + clean_sorting = apply_curation(sorting, curation_dict=curation_dict) + + # apply the curation to the sorting analyzer + clean_sorting_analyzer = apply_curation(sorting_analyzer, curation_dict=curation_dict) Using the ``SpikeInterface GUI`` diff --git a/examples/how_to/handle_drift.py b/examples/how_to/handle_drift.py index ecf17a1b1f..d324fd1f0f 100644 --- a/examples/how_to/handle_drift.py +++ b/examples/how_to/handle_drift.py @@ -2,12 +2,12 @@ # jupyter: # jupytext: # cell_metadata_filter: -all -# formats: py,ipynb +# formats: py:light,ipynb # text_representation: # extension: .py # format_name: light # format_version: '1.5' -# jupytext_version: 1.14.6 +# jupytext_version: 1.16.2 # kernelspec: # display_name: Python 3 (ipykernel) # language: python @@ -55,6 +55,8 @@ import spikeinterface.full as si +from spikeinterface.preprocessing import get_motion_parameters_preset, get_motion_presets + # - base_folder = Path("/mnt/data/sam/DataSpikeSorting/imposed_motion_nick") @@ -70,6 +72,7 @@ def preprocess_chain(rec): + rec = rec.astype('float32') rec = si.bandpass_filter(rec, freq_min=300.0, freq_max=6000.0) rec = si.common_reference(rec, reference="global", operator="median") return rec @@ -79,33 +82,46 @@ def preprocess_chain(rec): job_kwargs = dict(n_jobs=40, chunk_duration="1s", progress_bar=True) -# ### Run motion correction with one function! +# # # Correcting for drift is easy! You just need to run a single function. -# We will try this function with 3 presets. +# We will try this function with some presets. # # Internally a preset is a dictionary of dictionaries containing all parameters for every steps. # # Here we also save the motion correction results into a folder to be able to load them later. -# internally, we can explore a preset like this -# every parameter can be overwritten at runtime -from spikeinterface.preprocessing.motion import motion_options_preset +# ### preset and parameters +# +# Motion correction has some steps and eevry step can be controlled by a method and related parameters. +# +# A preset is a nested dict that contains theses methods/parameters. + +preset_keys = get_motion_presets() +preset_keys + +one_preset_params = get_motion_parameters_preset("kilosort_like") +one_preset_params + +# ### Run motion correction with one function! +# +# Correcting for drift is easy! You just need to run a single function. +# We will try this function with some presets. +# +# Here we also save the motion correction results into a folder to be able to load them later. -motion_options_preset["kilosort_like"] +# lets try theses presets +some_presets = ("rigid_fast", "kilosort_like", "nonrigid_accurate", "nonrigid_fast_and_accurate", "dredge", "dredge_fast") -# lets try theses 3 presets -some_presets = ("rigid_fast", "kilosort_like", "nonrigid_accurate") -# some_presets = ('kilosort_like', ) -# compute motion with 3 presets +# compute motion with theses presets for preset in some_presets: print("Computing with", preset) folder = base_folder / "motion_folder_dataset1" / preset if folder.exists(): shutil.rmtree(folder) - recording_corrected, motion_info = si.correct_motion( - rec, preset=preset, folder=folder, output_motion_info=True, **job_kwargs + recording_corrected, motion, motion_info = si.correct_motion( + rec, preset=preset, folder=folder, output_motion=True, output_motion_info=True, **job_kwargs ) # ### Plot the results @@ -127,11 +143,20 @@ def preprocess_chain(rec): # The motion vector is computed for different depths. # The corrected peak locations are flatter than the rigid case. # The motion vector map is still be a bit noisy at some depths (e.g around 1000um). -# * The preset **nonrigid_accurate** seems to give the best results on this recording. -# The motion vector seems less noisy globally, but it is not "perfect" (see at the top of the probe 3200um to 3800um). -# Also note that in the first part of the recording before the imposed motion (0-600s) we clearly have a non-rigid motion: +# * The preset **dredge** is offcial DREDge re-implementation in spikeinterface. +# It give the best result : very fast and smooth motion estimation. Very few noise. +# This method also capture very well the non rigid motion gradient along the probe. +# The best method on the market at the moement. +# An enormous thanks to the dream team : Charlie Windolf, Julien Boussard, Erdem Varol, Liam Paninski. +# Note that in the first part of the recording before the imposed motion (0-600s) we clearly have a non-rigid motion: # the upper part of the probe (2000-3000um) experience some drifts, but the lower part (0-1000um) is relatively stable. # The method defined by this preset is able to capture this. +# * The preset **nonrigid_accurate** this is the ancestor of "dredge" before it was published. +# It seems to give the good results on this recording but with bit more noise. +# * The preset **dredge_fast** similar than dredge but faster (using grid_convolution). +# * The preset **nonrigid_fast_and_accurate** a variant of nonrigid_accurate but faster (using grid_convolution). +# +# for preset in some_presets: # load @@ -140,8 +165,8 @@ def preprocess_chain(rec): # and plot fig = plt.figure(figsize=(14, 8)) - si.plot_motion( - motion_info, + si.plot_motion_info( + motion_info, rec, figure=fig, depth_lim=(400, 600), color_amplitude=True, @@ -173,6 +198,8 @@ def preprocess_chain(rec): folder = base_folder / "motion_folder_dataset1" / preset motion_info = si.load_motion_info(folder) + motion = motion_info["motion"] + fig, axs = plt.subplots(ncols=2, figsize=(12, 8), sharey=True) ax = axs[0] @@ -190,24 +217,16 @@ def preprocess_chain(rec): color_kargs = dict(alpha=0.2, s=2, c=c) - loc = motion_info["peak_locations"] + peak_locations = motion_info["peak_locations"] # color='black', - ax.scatter(loc["x"][mask][sl], loc["y"][mask][sl], **color_kargs) - - loc2 = correct_motion_on_peaks( - motion_info["peaks"], - motion_info["peak_locations"], - rec.sampling_frequency, - motion_info["motion"], - motion_info["temporal_bins"], - motion_info["spatial_bins"], - direction="y", - ) + ax.scatter(peak_locations["x"][mask][sl], peak_locations["y"][mask][sl], **color_kargs) + + peak_locations2 = correct_motion_on_peaks(peaks, peak_locations, motion,rec) ax = axs[1] si.plot_probe_map(rec, ax=ax) # color='black', - ax.scatter(loc2["x"][mask][sl], loc2["y"][mask][sl], **color_kargs) + ax.scatter(peak_locations2["x"][mask][sl], peak_locations2["y"][mask][sl], **color_kargs) ax.set_ylim(400, 600) fig.suptitle(f"{preset=}") @@ -228,7 +247,7 @@ def preprocess_chain(rec): keys = run_times[0].keys() bottom = np.zeros(len(run_times)) -fig, ax = plt.subplots() +fig, ax = plt.subplots(figsize=(14, 6)) for k in keys: rtimes = np.array([rt[k] for rt in run_times]) if np.any(rtimes > 0.0): diff --git a/pyproject.toml b/pyproject.toml index 54afc98fdc..67aee92d29 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -139,6 +139,7 @@ test_extractors = [ test_preprocessing = [ "ibllib>=2.36.0", # for IBL + "torch", ] diff --git a/src/spikeinterface/core/sorting_tools.py b/src/spikeinterface/core/sorting_tools.py index 6994575150..5f33350820 100644 --- a/src/spikeinterface/core/sorting_tools.py +++ b/src/spikeinterface/core/sorting_tools.py @@ -227,7 +227,7 @@ def random_spikes_selection( def apply_merges_to_sorting( - sorting, merge_unit_groups, new_unit_ids=None, censor_ms=None, return_kept=False, new_id_strategy="append" + sorting, merge_unit_groups, new_unit_ids=None, censor_ms=None, return_extra=False, new_id_strategy="append" ): """ Apply a resolved representation of the merges to a sorting object. @@ -250,8 +250,8 @@ def apply_merges_to_sorting( merged units will have the first unit_id of every lists of merges. censor_ms: float | None, default: None When applying the merges, should be discard consecutive spikes violating a given refractory per - return_kept : bool, default: False - If True, also return also a boolean mask of kept spikes. + return_extra : bool, default: False + If True, also return also a boolean mask of kept spikes and new_unit_ids. new_id_strategy : "append" | "take_first", default: "append" The strategy that should be used, if `new_unit_ids` is None, to create new unit_ids. @@ -316,8 +316,8 @@ def apply_merges_to_sorting( spikes = spikes[keep_mask] sorting = NumpySorting(spikes, sorting.sampling_frequency, all_unit_ids) - if return_kept: - return sorting, keep_mask + if return_extra: + return sorting, keep_mask, new_unit_ids else: return sorting @@ -384,11 +384,13 @@ def generate_unit_ids_for_merge_group(old_unit_ids, merge_unit_groups, new_unit_ new_unit_ids : list | None, default: None Optional new unit_ids for merged units. If given, it needs to have the same length as `merge_unit_groups`. If None, new ids will be generated. - new_id_strategy : "append" | "take_first", default: "append" + new_id_strategy : "append" | "take_first" | "join", default: "append" The strategy that should be used, if `new_unit_ids` is None, to create new unit_ids. * "append" : new_units_ids will be added at the end of max(sorging.unit_ids) * "take_first" : new_unit_ids will be the first unit_id of every list of merges + * "join" : new_unit_ids will join unit_ids of groups with a "-". + Only works if unit_ids are str otherwise switch to "append" Returns ------- @@ -423,6 +425,12 @@ def generate_unit_ids_for_merge_group(old_unit_ids, merge_unit_groups, new_unit_ else: # dtype int new_unit_ids = list(max(old_unit_ids) + 1 + np.arange(num_merge, dtype=dtype)) + elif new_id_strategy == "join": + if np.issubdtype(dtype, np.character): + new_unit_ids = ["-".join(group) for group in merge_unit_groups] + else: + # dtype int + new_unit_ids = list(max(old_unit_ids) + 1 + np.arange(num_merge, dtype=dtype)) else: raise ValueError("wrong new_id_strategy") diff --git a/src/spikeinterface/core/sortinganalyzer.py b/src/spikeinterface/core/sortinganalyzer.py index 1f3479f130..ac142405ab 100644 --- a/src/spikeinterface/core/sortinganalyzer.py +++ b/src/spikeinterface/core/sortinganalyzer.py @@ -732,12 +732,12 @@ def _save_or_select_or_merge( else: from spikeinterface.core.sorting_tools import apply_merges_to_sorting - sorting_provenance, keep_mask = apply_merges_to_sorting( + sorting_provenance, keep_mask, _ = apply_merges_to_sorting( sorting=sorting_provenance, merge_unit_groups=merge_unit_groups, new_unit_ids=new_unit_ids, censor_ms=censor_ms, - return_kept=True, + return_extra=True, ) if censor_ms is None: # in this case having keep_mask None is faster instead of having a vector of ones @@ -885,6 +885,7 @@ def merge_units( merging_mode="soft", sparsity_overlap=0.75, new_id_strategy="append", + return_new_unit_ids=False, format="memory", folder=None, verbose=False, @@ -917,6 +918,8 @@ def merge_units( The strategy that should be used, if `new_unit_ids` is None, to create new unit_ids. * "append" : new_units_ids will be added at the end of max(sorting.unit_ids) * "take_first" : new_unit_ids will be the first unit_id of every list of merges + return_new_unit_ids : bool, default False + Alse return new_unit_ids which are the ids of the new units. folder : Path | None, default: None The new folder where the analyzer with merged units is copied for `format` "binary_folder" or "zarr" format : "memory" | "binary_folder" | "zarr", default: "memory" @@ -924,7 +927,6 @@ def merge_units( verbose : bool, default: False Whether to display calculations (such as sparsity estimation) - Returns ------- analyzer : SortingAnalyzer @@ -952,7 +954,7 @@ def merge_units( ) all_unit_ids = _get_ids_after_merging(self.unit_ids, merge_unit_groups, new_unit_ids=new_unit_ids) - return self._save_or_select_or_merge( + new_analyzer = self._save_or_select_or_merge( format=format, folder=folder, merge_unit_groups=merge_unit_groups, @@ -964,6 +966,10 @@ def merge_units( new_unit_ids=new_unit_ids, **job_kwargs, ) + if return_new_unit_ids: + return new_analyzer, new_unit_ids + else: + return new_analyzer def copy(self): """ diff --git a/src/spikeinterface/core/tests/test_sorting_tools.py b/src/spikeinterface/core/tests/test_sorting_tools.py index 6d0e61f844..34bb3a221d 100644 --- a/src/spikeinterface/core/tests/test_sorting_tools.py +++ b/src/spikeinterface/core/tests/test_sorting_tools.py @@ -96,7 +96,7 @@ def test_apply_merges_to_sorting(): spikes1[spikes1["unit_index"] == 2]["sample_index"], spikes2[spikes2["unit_index"] == 0]["sample_index"] ) - sorting3, keep_mask = apply_merges_to_sorting(sorting1, [["a", "b"]], censor_ms=1.5, return_kept=True) + sorting3, keep_mask, _ = apply_merges_to_sorting(sorting1, [["a", "b"]], censor_ms=1.5, return_extra=True) spikes3 = sorting3.to_spike_vector() assert spikes3.size < spikes1.size assert not keep_mask[1] @@ -153,6 +153,11 @@ def test_generate_unit_ids_for_merge_group(): ) assert np.array_equal(new_unit_ids, ["0", "9"]) + new_unit_ids = generate_unit_ids_for_merge_group( + ["0", "5", "12", "9", "15"], [["0", "5"], ["9", "15"]], new_id_strategy="join" + ) + assert np.array_equal(new_unit_ids, ["0-5", "9-15"]) + if __name__ == "__main__": # test_spike_vector_to_spike_trains() diff --git a/src/spikeinterface/curation/curation_format.py b/src/spikeinterface/curation/curation_format.py index fc75f74399..88190a9bab 100644 --- a/src/spikeinterface/curation/curation_format.py +++ b/src/spikeinterface/curation/curation_format.py @@ -1,5 +1,9 @@ from itertools import combinations +import numpy as np + +from spikeinterface.core import BaseSorting, SortingAnalyzer, apply_merges_to_sorting +import copy supported_curation_format_versions = {"1"} @@ -119,9 +123,9 @@ def convert_from_sortingview_curation_format_v0(sortingview_dict, destination_fo return curation_dict -def curation_label_to_dataframe(curation_dict): +def curation_label_to_vectors(curation_dict): """ - Transform the curation dict into a pandas dataframe. + Transform the curation dict into dict of vectors. For label category with exclusive=True : a column is created and values are the unique label. For label category with exclusive=False : one column per possible is created and values are boolean. @@ -134,30 +138,218 @@ def curation_label_to_dataframe(curation_dict): Returns ------- - labels : pd.DataFrame - dataframe with labels. + labels: dict of numpy vector + """ - import pandas as pd + unit_ids = list(curation_dict["unit_ids"]) + n = len(unit_ids) - labels = pd.DataFrame(index=curation_dict["unit_ids"]) + labels = {} for label_key, label_def in curation_dict["label_definitions"].items(): if label_def["exclusive"]: - assert label_key not in labels.columns, f"{label_key} is already a column" - labels[label_key] = pd.Series(dtype=str) - labels[label_key][:] = "" + assert label_key not in labels, f"{label_key} is already a key" + labels[label_key] = [""] * n for lbl in curation_dict["manual_labels"]: value = lbl.get(label_key, []) if len(value) == 1: - labels.at[lbl["unit_id"], label_key] = value[0] + unit_index = unit_ids.index(lbl["unit_id"]) + labels[label_key][unit_index] = value[0] + labels[label_key] = np.array(labels[label_key]) else: for label_opt in label_def["label_options"]: - assert label_opt not in labels.columns, f"{label_opt} is already a column" - labels[label_opt] = pd.Series(dtype=bool) - labels[label_opt][:] = False + assert label_opt not in labels, f"{label_opt} is already a key" + labels[label_opt] = np.zeros(n, dtype=bool) for lbl in curation_dict["manual_labels"]: values = lbl.get(label_key, []) for value in values: - labels.at[lbl["unit_id"], value] = True + unit_index = unit_ids.index(lbl["unit_id"]) + labels[value][unit_index] = True + + return labels + + +def clean_curation_dict(curation_dict): + """ + In some cases the curation_dict can have inconsistencies (like in the sorting view format). + For instance, some unit_ids are both in 'merge_unit_groups' and 'removed_units'. + This is ambiguous! + + This cleaner helper function ensures units tagged as `removed_units` are removed from the `merge_unit_groups` + """ + curation_dict = copy.deepcopy(curation_dict) + + clean_merge_unit_groups = [] + for group in curation_dict["merge_unit_groups"]: + clean_group = [] + for unit_id in group: + if unit_id not in curation_dict["removed_units"]: + clean_group.append(unit_id) + if len(clean_group) > 1: + clean_merge_unit_groups.append(clean_group) + + curation_dict["merge_unit_groups"] = clean_merge_unit_groups + return curation_dict + + +def curation_label_to_dataframe(curation_dict): + """ + Transform the curation dict into a pandas dataframe. + For label category with exclusive=True : a column is created and values are the unique label. + For label category with exclusive=False : one column per possible is created and values are boolean. + + If exclusive=False and the same label appears several times then an error is raised. + + Parameters + ---------- + curation_dict : dict + A curation dictionary + + Returns + ------- + labels : pd.DataFrame + dataframe with labels. + """ + import pandas as pd + labels = pd.DataFrame(curation_label_to_vectors(curation_dict), index=curation_dict["unit_ids"]) return labels + + +def apply_curation_labels(sorting, new_unit_ids, curation_dict): + """ + Apply manual labels after merges. + + Rules: + * label for non merge is applied first + * for merged group, when exclusive=True, if all have the same label then this label is applied + * for merged group, when exclusive=False, if one unit has the label then the new one have also it + """ + + # Please note that manual_labels is done on the unit_ids before the merge!!! + manual_labels = curation_label_to_vectors(curation_dict) + + # apply on non merged + for key, values in manual_labels.items(): + all_values = np.zeros(sorting.unit_ids.size, dtype=values.dtype) + for unit_ind, unit_id in enumerate(sorting.unit_ids): + if unit_id not in new_unit_ids: + ind = curation_dict["unit_ids"].index(unit_id) + all_values[unit_ind] = values[ind] + sorting.set_property(key, all_values) + + for new_unit_id, old_group_ids in zip(new_unit_ids, curation_dict["merge_unit_groups"]): + for label_key, label_def in curation_dict["label_definitions"].items(): + if label_def["exclusive"]: + group_values = [] + for unit_id in old_group_ids: + ind = curation_dict["unit_ids"].index(unit_id) + value = manual_labels[label_key][ind] + if value != "": + group_values.append(value) + if len(set(group_values)) == 1: + # all group has the same label or empty + sorting.set_property(key, values=group_values, ids=[new_unit_id]) + else: + + for key in label_def["label_options"]: + group_values = [] + for unit_id in old_group_ids: + ind = curation_dict["unit_ids"].index(unit_id) + value = manual_labels[key][ind] + group_values.append(value) + new_value = np.any(group_values) + sorting.set_property(key, values=[new_value], ids=[new_unit_id]) + + +def apply_curation( + sorting_or_analyzer, + curation_dict, + censor_ms=None, + new_id_strategy="append", + merging_mode="soft", + sparsity_overlap=0.75, + verbose=False, + **job_kwargs, +): + """ + Apply curation dict to a Sorting or a SortingAnalyzer. + + Steps are done in this order: + 1. Apply removal using curation_dict["removed_units"] + 2. Apply merges using curation_dict["merge_unit_groups"] + 3. Set labels using curation_dict["manual_labels"] + + A new Sorting or SortingAnalyzer (in memory) is returned. + The user (an adult) has the responsability to save it somewhere (or not). + + Parameters + ---------- + sorting_or_analyzer : Sorting | SortingAnalyzer + The Sorting object to apply merges. + curation_dict : dict + The curation dict. + censor_ms: float | None, default: None + When applying the merges, any consecutive spikes within the `censor_ms` are removed. This can be thought of + as the desired refractory period. If `censor_ms=None`, no spikes are discarded. + new_id_strategy : "append" | "take_first", default: "append" + The strategy that should be used, if `new_unit_ids` is None, to create new unit_ids. + + * "append" : new_units_ids will be added at the end of max(sorting.unit_ids) + * "take_first" : new_unit_ids will be the first unit_id of every list of merges + merging_mode : "soft" | "hard", default: "soft" + How merges are performed for SortingAnalyzer. If the `merge_mode` is "soft" , merges will be approximated, with no reloading of + the waveforms. This will lead to approximations. If `merge_mode` is "hard", recomputations are accurately + performed, reloading waveforms if needed + sparsity_overlap : float, default 0.75 + The percentage of overlap that units should share in order to accept merges. If this criteria is not + achieved, soft merging will not be possible and an error will be raised. This is for use with a SortingAnalyzer input. + + verbose: + + **job_kwargs + + Returns + ------- + sorting_or_analyzer : Sorting | SortingAnalyzer + The curated object. + + + """ + validate_curation_dict(curation_dict) + if not np.array_equal(np.asarray(curation_dict["unit_ids"]), sorting_or_analyzer.unit_ids): + raise ValueError("unit_ids from the curation_dict do not match the one from Sorting or SortingAnalyzer") + + if isinstance(sorting_or_analyzer, BaseSorting): + sorting = sorting_or_analyzer + sorting = sorting.remove_units(curation_dict["removed_units"]) + sorting, _, new_unit_ids = apply_merges_to_sorting( + sorting, + curation_dict["merge_unit_groups"], + censor_ms=censor_ms, + return_extra=True, + new_id_strategy=new_id_strategy, + ) + apply_curation_labels(sorting, new_unit_ids, curation_dict) + return sorting + + elif isinstance(sorting_or_analyzer, SortingAnalyzer): + analyzer = sorting_or_analyzer + analyzer = analyzer.remove_units(curation_dict["removed_units"]) + analyzer, new_unit_ids = analyzer.merge_units( + curation_dict["merge_unit_groups"], + censor_ms=censor_ms, + merging_mode=merging_mode, + sparsity_overlap=sparsity_overlap, + new_id_strategy=new_id_strategy, + return_new_unit_ids=True, + format="memory", + verbose=verbose, + **job_kwargs, + ) + apply_curation_labels(analyzer.sorting, new_unit_ids, curation_dict) + return analyzer + else: + raise TypeError( + f"`sorting_or_analyzer` must be a Sorting or a SortingAnalyzer, not an object of type {type(sorting_or_analyzer)}" + ) diff --git a/src/spikeinterface/curation/sortingview_curation.py b/src/spikeinterface/curation/sortingview_curation.py index c4d2a32958..1e36183eed 100644 --- a/src/spikeinterface/curation/sortingview_curation.py +++ b/src/spikeinterface/curation/sortingview_curation.py @@ -1,14 +1,116 @@ from __future__ import annotations + +import warnings + import json import numpy as np from pathlib import Path from .curationsorting import CurationSorting +from .curation_format import ( + convert_from_sortingview_curation_format_v0, + apply_curation, + curation_label_to_vectors, + clean_curation_dict, +) -# @alessio -# TODO later : this should be reimplemented using the new curation format def apply_sortingview_curation( + sorting_or_analyzer, uri_or_json, exclude_labels=None, include_labels=None, skip_merge=False, verbose=None +): + """ + Apply curation from SortingView manual legacy curation format (before the official "curation_format") + + First, merges (if present) are applied. Then labels are loaded and units + are optionally filtered based on exclude_labels and include_labels. + + Parameters + ---------- + sorting_or_analyzer : Sorting | SortingAnalyzer + The sorting or analyzer to be curated + uri_or_json : str or Path + The URI curation link from SortingView or the path to the curation json file + exclude_labels : list, default: None + Optional list of labels to exclude (e.g. ["reject", "noise"]). + Mutually exclusive with include_labels + include_labels : list, default: None + Optional list of labels to include (e.g. ["accept"]). + Mutually exclusive with exclude_labels, by default None + skip_merge : bool, default: False + If True, merges are not applied (only labels) + verbose : None + Deprecated + + + Returns + ------- + sorting_or_analyzer_curated : BaseSorting + The curated sorting or analyzer + """ + + if verbose is not None: + warnings.warn("versobe in apply_sortingview_curation() is deprecated") + + # download + if Path(uri_or_json).suffix == ".json" and not str(uri_or_json).startswith("gh://"): + with open(uri_or_json, "r") as f: + curation_dict = json.load(f) + else: + try: + import kachery_cloud as kcl + except ImportError: + raise ImportError( + "To apply a SortingView manual curation, you need to have sortingview installed: " + ">>> pip install sortingview" + ) + + try: + curation_dict = kcl.load_json(uri=uri_or_json) + except: + raise Exception(f"Could not retrieve curation from SortingView uri: {uri_or_json}") + + # convert to new format + if "format_version" not in curation_dict: + curation_dict = convert_from_sortingview_curation_format_v0(curation_dict) + + unit_ids = sorting_or_analyzer.unit_ids + + # this is a hack because it was not in the old format + curation_dict["unit_ids"] = list(unit_ids) + + if exclude_labels is not None: + assert include_labels is None, "Use either `include_labels` or `exclude_labels` to filter units." + manual_labels = curation_label_to_vectors(curation_dict) + removed_units = [] + for k in exclude_labels: + remove_mask = manual_labels[k] + removed_units.extend(unit_ids[remove_mask]) + removed_units = np.unique(removed_units) + curation_dict["removed_units"] = removed_units + + if include_labels is not None: + manual_labels = curation_label_to_vectors(curation_dict) + removed_units = [] + for k in include_labels: + remove_mask = ~manual_labels[k] + removed_units.extend(unit_ids[remove_mask]) + removed_units = np.unique(removed_units) + curation_dict["removed_units"] = removed_units + + if skip_merge: + curation_dict["merge_unit_groups"] = [] + + # cleaner to ensure validity + curation_dict = clean_curation_dict(curation_dict) + + # apply + sorting_curated = apply_curation(sorting_or_analyzer, curation_dict, new_id_strategy="join") + + return sorting_curated + + +# TODO @alessio you remove this after testing +def apply_sortingview_curation_legacy( sorting, uri_or_json, exclude_labels=None, include_labels=None, skip_merge=False, verbose=False ): """ diff --git a/src/spikeinterface/curation/tests/test_curation_format.py b/src/spikeinterface/curation/tests/test_curation_format.py index 94812ee0aa..af9d8e1eac 100644 --- a/src/spikeinterface/curation/tests/test_curation_format.py +++ b/src/spikeinterface/curation/tests/test_curation_format.py @@ -2,11 +2,16 @@ from pathlib import Path import json +import numpy as np + +from spikeinterface.core import generate_ground_truth_recording, create_sorting_analyzer from spikeinterface.curation.curation_format import ( validate_curation_dict, convert_from_sortingview_curation_format_v0, + curation_label_to_vectors, curation_label_to_dataframe, + apply_curation, ) @@ -141,6 +146,17 @@ def test_convert_from_sortingview_curation_format_v0(): validate_curation_dict(curation_v1) +def test_curation_label_to_vectors(): + + labels = curation_label_to_vectors(curation_ids_int) + assert "quality" in labels + assert "excitatory" in labels + print(labels) + + labels = curation_label_to_vectors(curation_ids_str) + print(labels) + + def test_curation_label_to_dataframe(): df = curation_label_to_dataframe(curation_ids_int) @@ -152,10 +168,25 @@ def test_curation_label_to_dataframe(): # print(df) +def test_apply_curation(): + recording, sorting = generate_ground_truth_recording(durations=[10.0], num_units=9, seed=2205) + sorting._main_ids = np.array([1, 2, 3, 6, 10, 14, 20, 31, 42]) + analyzer = create_sorting_analyzer(sorting, recording, sparse=False) + + sorting_curated = apply_curation(sorting, curation_ids_int) + assert sorting_curated.get_property("quality", ids=[1])[0] == "good" + assert sorting_curated.get_property("quality", ids=[2])[0] == "noise" + assert sorting_curated.get_property("excitatory", ids=[2])[0] + + analyzer_curated = apply_curation(analyzer, curation_ids_int) + assert "quality" in analyzer_curated.sorting.get_property_keys() + + if __name__ == "__main__": # test_curation_format_validation() # test_to_from_json() # test_convert_from_sortingview_curation_format_v0() + # test_curation_label_to_vectors() # test_curation_label_to_dataframe() - print(json.dumps(curation_ids_str, indent=4)) + test_apply_curation() diff --git a/src/spikeinterface/curation/tests/test_sortingview_curation.py b/src/spikeinterface/curation/tests/test_sortingview_curation.py index 00721ff34d..bb152e7f71 100644 --- a/src/spikeinterface/curation/tests/test_sortingview_curation.py +++ b/src/spikeinterface/curation/tests/test_sortingview_curation.py @@ -52,7 +52,7 @@ def test_gh_curation(): # curated link: # https://figurl.org/f?v=npm://@fi-sci/figurl-sortingview@12/dist&d=sha1://058ab901610aa9d29df565595a3cc2a81a1b08e5 gh_uri = "gh://SpikeInterface/spikeinterface/main/src/spikeinterface/curation/tests/sv-sorting-curation.json" - sorting_curated_gh = apply_sortingview_curation(sorting, uri_or_json=gh_uri, verbose=True) + sorting_curated_gh = apply_sortingview_curation(sorting, uri_or_json=gh_uri) assert len(sorting_curated_gh.unit_ids) == 9 assert 1, 2 in sorting_curated_gh.unit_ids @@ -81,7 +81,7 @@ def test_sha1_curation(): # curated link: # https://figurl.org/f?v=npm://@fi-sci/figurl-sortingview@12/dist&d=sha1://058ab901610aa9d29df565595a3cc2a81a1b08e5 sha1_uri = "sha1://449a428e8824eef9ad9bcc3241e45a2cee02d381" - sorting_curated_sha1 = apply_sortingview_curation(sorting, uri_or_json=sha1_uri, verbose=True) + sorting_curated_sha1 = apply_sortingview_curation(sorting, uri_or_json=sha1_uri) # print(f"From SHA: {sorting_curated_sha1}") assert len(sorting_curated_sha1.unit_ids) == 9 @@ -109,7 +109,7 @@ def test_json_curation(): # from curation.json json_file = parent_folder / "sv-sorting-curation.json" # print(f"Sorting: {sorting.get_unit_ids()}") - sorting_curated_json = apply_sortingview_curation(sorting, uri_or_json=json_file, verbose=True) + sorting_curated_json = apply_sortingview_curation(sorting, uri_or_json=json_file) assert len(sorting_curated_json.unit_ids) == 9 assert 1, 2 in sorting_curated_json.unit_ids @@ -146,7 +146,7 @@ def test_false_positive_curation(): # print("Sorting: {}".format(sorting.get_unit_ids())) json_file = parent_folder / "sv-sorting-curation-false-positive.json" - sorting_curated_json = apply_sortingview_curation(sorting, uri_or_json=json_file, verbose=True) + sorting_curated_json = apply_sortingview_curation(sorting, uri_or_json=json_file) # print("Curated:", sorting_curated_json.get_unit_ids()) # Assertions @@ -190,17 +190,13 @@ def test_label_inheritance_int(): assert not sorting_merge.get_unit_property(unit_id=10, key="noise") assert sorting_merge.get_unit_property(unit_id=10, key="accept") - # Assertions for exclude_labels + # Assertions for exclude_labels should all be False sorting_exclude_noise = apply_sortingview_curation(sorting, uri_or_json=json_file, exclude_labels=["noise"]) - # print(f"Exclude noise: {sorting_exclude_noise.get_unit_ids()}") - assert 9 not in sorting_exclude_noise.get_unit_ids() + assert np.all(~sorting_exclude_noise.get_property("noise")) # Assertions for include_labels sorting_include_accept = apply_sortingview_curation(sorting, uri_or_json=json_file, include_labels=["accept"]) - # print(f"Include accept: {sorting_include_accept.get_unit_ids()}") - assert 8 not in sorting_include_accept.get_unit_ids() - assert 9 not in sorting_include_accept.get_unit_ids() - assert 10 in sorting_include_accept.get_unit_ids() + assert np.all(sorting_include_accept.get_property("accept")) def test_label_inheritance_str(): @@ -219,7 +215,7 @@ def test_label_inheritance_str(): # Apply curation json_file = parent_folder / "sv-sorting-curation-str.json" - sorting_merge = apply_sortingview_curation(sorting, uri_or_json=json_file, verbose=True) + sorting_merge = apply_sortingview_curation(sorting, uri_or_json=json_file) # Assertions for merged units # print(f"Merge only: {sorting_merge.get_unit_ids()}") @@ -238,22 +234,18 @@ def test_label_inheritance_str(): assert not sorting_merge.get_unit_property(unit_id="e-f", key="noise") assert sorting_merge.get_unit_property(unit_id="e-f", key="accept") - # Assertions for exclude_labels + # Assertions for exclude_labels should all be False sorting_exclude_noise = apply_sortingview_curation(sorting, uri_or_json=json_file, exclude_labels=["noise"]) - # print(f"Exclude noise: {sorting_exclude_noise.get_unit_ids()}") - assert "c-d" not in sorting_exclude_noise.get_unit_ids() + assert np.all(~sorting_exclude_noise.get_property("noise")) # Assertions for include_labels sorting_include_accept = apply_sortingview_curation(sorting, uri_or_json=json_file, include_labels=["accept"]) - # print(f"Include accept: {sorting_include_accept.get_unit_ids()}") - assert "a-b" not in sorting_include_accept.get_unit_ids() - assert "c-d" not in sorting_include_accept.get_unit_ids() - assert "e-f" in sorting_include_accept.get_unit_ids() + assert np.all(sorting_include_accept.get_property("accept")) if __name__ == "__main__": # generate_sortingview_curation_dataset() - test_sha1_curation() + # test_sha1_curation() test_gh_curation() test_json_curation() test_false_positive_curation() diff --git a/src/spikeinterface/generation/drift_tools.py b/src/spikeinterface/generation/drift_tools.py index 70e13160f4..0e4f1985c6 100644 --- a/src/spikeinterface/generation/drift_tools.py +++ b/src/spikeinterface/generation/drift_tools.py @@ -262,9 +262,14 @@ def make_linear_displacement(start, stop, num_step=10): displacements : np.array The displacements with shape (num_step, 2) """ - displacements = (stop[np.newaxis, :] - start[np.newaxis, :]) / (num_step - 1) * np.arange(num_step)[ - :, np.newaxis - ] + start[np.newaxis, :] + if num_step < 1: + raise ValueError("make_linear_displacement needs num_step > 0") + if num_step == 1: + displacements = ((start + stop) / 2)[np.newaxis, :] + else: + displacements = (stop[np.newaxis, :] - start[np.newaxis, :]) / (num_step - 1) * np.arange(num_step)[ + :, np.newaxis + ] + start[np.newaxis, :] return displacements diff --git a/src/spikeinterface/generation/hybrid_tools.py b/src/spikeinterface/generation/hybrid_tools.py index 2806754c9d..0c82e496c0 100644 --- a/src/spikeinterface/generation/hybrid_tools.py +++ b/src/spikeinterface/generation/hybrid_tools.py @@ -517,6 +517,7 @@ def generate_hybrid_recording( elif dim == 2: raise NotImplementedError("3D motion not implemented yet") num_step = int((stop - start)[dim] / drift_step_um) + num_step = max(1, num_step) displacements = make_linear_displacement(start, stop, num_step=num_step) # use templates_, because templates_array might have been scaled diff --git a/src/spikeinterface/generation/tests/test_hybrid_tools.py b/src/spikeinterface/generation/tests/test_hybrid_tools.py index bdcd8dbb8f..535b3e63a1 100644 --- a/src/spikeinterface/generation/tests/test_hybrid_tools.py +++ b/src/spikeinterface/generation/tests/test_hybrid_tools.py @@ -79,7 +79,7 @@ def test_estimate_templates(create_cache_folder): if __name__ == "__main__": - test_generate_hybrid_no_motion() + # test_generate_hybrid_no_motion() test_generate_hybrid_motion() - test_estimate_templates() - test_generate_hybrid_with_sorting() + # test_estimate_templates() + # test_generate_hybrid_with_sorting() diff --git a/src/spikeinterface/preprocessing/__init__.py b/src/spikeinterface/preprocessing/__init__.py index 5f9ac046e1..3343217090 100644 --- a/src/spikeinterface/preprocessing/__init__.py +++ b/src/spikeinterface/preprocessing/__init__.py @@ -1,6 +1,6 @@ from .preprocessinglist import * -from .motion import correct_motion, load_motion_info, save_motion_info +from .motion import correct_motion, load_motion_info, save_motion_info, get_motion_parameters_preset, get_motion_presets from .preprocessing_tools import get_spatial_interpolation_kernel from .detect_bad_channels import detect_bad_channels diff --git a/src/spikeinterface/preprocessing/motion.py b/src/spikeinterface/preprocessing/motion.py index 8e9911b47e..8d1f9bc9f3 100644 --- a/src/spikeinterface/preprocessing/motion.py +++ b/src/spikeinterface/preprocessing/motion.py @@ -1,10 +1,12 @@ from __future__ import annotations +import copy import numpy as np import json import shutil from pathlib import Path import time +import inspect from spikeinterface.core import get_noise_levels, fix_job_kwargs from spikeinterface.core.job_tools import _shared_job_kwargs_doc @@ -12,9 +14,9 @@ from spikeinterface.core.job_tools import _shared_job_kwargs_doc motion_options_preset = { - # This preset should be the most acccurate - "nonrigid_accurate": { - "doc": "method by Paninski lab (monopolar_triangulation + decentralized)", + # dredge + "dredge": { + "doc": "Official Dredge preset", "detect_kwargs": dict( method="locally_exclusive", peak_sign="neg", @@ -25,52 +27,23 @@ "select_kwargs": dict(), "localize_peaks_kwargs": dict( method="monopolar_triangulation", - radius_um=75.0, - max_distance_um=150.0, - optimizer="minimize_with_log_penality", - enforce_decrease=True, - # feature="peak_voltage", - feature="ptp", ), "estimate_motion_kwargs": dict( - method="decentralized", + method="dredge_ap", direction="y", - bin_s=1.0, rigid=False, - bin_um=5.0, - hist_margin_um=20.0, win_shape="gaussian", - win_step_um=200.0, - win_scale_um=300.0, - histogram_depth_smooth_um=5.0, - histogram_time_smooth_s=None, - pairwise_displacement_method="conv", - max_displacement_um=100.0, - weight_scale="linear", - error_sigma=0.2, - conv_engine=None, - torch_device=None, - batch_size=1, - corr_threshold=0.0, - time_horizon_s=None, - convergence_method="lsmr", - soft_weights=False, - normalized_xcorr=True, - centered_xcorr=True, - temporal_prior=True, - spatial_prior=False, - force_spatial_median_continuity=False, - reference_displacement="median", - reference_displacement_time_s=0, - robust_regression_sigma=2, - weight_with_amplitude=False, + win_step_um=400.0, + win_scale_um=400.0, + win_margin_um=None, ), "interpolate_motion_kwargs": dict( - border_mode="remove_channels", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 + border_mode="force_extrapolate", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 ), }, - "nonrigid_fast_and_accurate": { - "doc": "mixed methods by KS & Paninski lab (grid_convolution + decentralized)", + # similar than dredge but faster + "dredge_fast": { + "doc": "Modified and faster Dredge preset", "detect_kwargs": dict( method="locally_exclusive", peak_sign="neg", @@ -81,48 +54,49 @@ "select_kwargs": dict(), "localize_peaks_kwargs": dict( method="grid_convolution", - # radius_um=40.0, - radius_um=80.0, - upsampling_um=5.0, - sigma_ms=0.25, - margin_um=30.0, - prototype=None, - percentile=5.0, ), "estimate_motion_kwargs": dict( - method="decentralized", + method="dredge_ap", direction="y", - bin_s=2.0, rigid=False, - bin_um=5.0, - hist_margin_um=0.0, win_shape="gaussian", - win_step_um=100.0, - win_scale_um=200.0, + win_step_um=400.0, + win_scale_um=400.0, win_margin_um=None, - histogram_depth_smooth_um=5.0, - histogram_time_smooth_s=None, - pairwise_displacement_method="conv", - max_displacement_um=100.0, - weight_scale="linear", - error_sigma=0.2, - conv_engine=None, - torch_device=None, - batch_size=1, - corr_threshold=0.0, - time_horizon_s=None, - convergence_method="lsmr", - soft_weights=False, - normalized_xcorr=True, - centered_xcorr=True, - temporal_prior=True, - spatial_prior=False, - force_spatial_median_continuity=False, - reference_displacement="median", - reference_displacement_time_s=0, - robust_regression_sigma=2, - weight_with_amplitude=False, ), + "interpolate_motion_kwargs": dict( + border_mode="force_extrapolate", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 + ), + }, + # This preset is the encestor of dredge + "nonrigid_accurate": { + "doc": "method by Paninski lab (monopolar_triangulation + decentralized)", + "detect_kwargs": dict( + method="locally_exclusive", + peak_sign="neg", + detect_threshold=8.0, + exclude_sweep_ms=0.8, + radius_um=80.0, + ), + "select_kwargs": dict(), + "localize_peaks_kwargs": dict(method="monopolar_triangulation"), + "estimate_motion_kwargs": dict(method="decentralized", direction="y", rigid=False), + "interpolate_motion_kwargs": dict( + border_mode="remove_channels", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 + ), + }, + "nonrigid_fast_and_accurate": { + "doc": "mixed methods by KS & Paninski lab (grid_convolution + decentralized)", + "detect_kwargs": dict( + method="locally_exclusive", + peak_sign="neg", + detect_threshold=8.0, + exclude_sweep_ms=0.8, + radius_um=80.0, + ), + "select_kwargs": dict(), + "localize_peaks_kwargs": dict(method="grid_convolution"), + "estimate_motion_kwargs": dict(method="decentralized", direction="y", rigid=False), "interpolate_motion_kwargs": dict( border_mode="remove_channels", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 ), @@ -135,19 +109,12 @@ peak_sign="neg", detect_threshold=8.0, exclude_sweep_ms=0.1, - radius_um=50, - ), - "select_kwargs": dict(), - "localize_peaks_kwargs": dict( - method="center_of_mass", radius_um=75.0, - feature="ptp", - ), - "estimate_motion_kwargs": dict( - method="decentralized", - bin_s=10.0, - rigid=True, ), + "select_kwargs": dict(), + # "localize_peaks_kwargs": dict(method="grid_convolution"), + "localize_peaks_kwargs": dict(method="center_of_mass"), + "estimate_motion_kwargs": dict(method="dredge_ap", bin_s=5.0, rigid=True), "interpolate_motion_kwargs": dict( border_mode="remove_channels", spatial_interpolation_method="kriging", sigma_um=20.0, p=2 ), @@ -165,20 +132,14 @@ "select_kwargs": dict(), "localize_peaks_kwargs": dict( method="grid_convolution", - radius_um=40.0, - upsampling_um=5.0, weight_method={"mode": "gaussian_2d", "sigma_list_um": np.linspace(5, 25, 5)}, - sigma_ms=0.25, - margin_um=30.0, - prototype=None, - percentile=5.0, ), "estimate_motion_kwargs": dict( method="iterative_template", bin_s=2.0, rigid=False, - win_step_um=50.0, - win_scale_um=150.0, + win_step_um=200.0, + win_scale_um=400.0, hist_margin_um=0, win_shape="rect", ), @@ -197,9 +158,93 @@ } +def _get_default_motion_params(): + # dirty code that inspect class to get parameters + # when multi method for detect_peak/localize_peak/estimate_motion + + params = dict() + + from spikeinterface.sortingcomponents.peak_detection import detect_peak_methods + from spikeinterface.sortingcomponents.peak_localization import localize_peak_methods + from spikeinterface.sortingcomponents.motion.motion_estimation import estimate_motion_methods, estimate_motion + + params["detect_kwargs"] = dict() + for method_name, method_class in detect_peak_methods.items(): + if hasattr(method_class, "check_params"): + sig = inspect.signature(method_class.check_params) + params["detect_kwargs"][method_name] = { + k: v.default for k, v in sig.parameters.items() if k != "self" and v.default != inspect.Parameter.empty + } + + # no design by subclass + params["select_kwargs"] = dict() + + params["localize_peaks_kwargs"] = dict() + for method_name, method_class in localize_peak_methods.items(): + sig = inspect.signature(method_class.__init__) + p = {k: v.default for k, v in sig.parameters.items() if k != "self" and v.default != inspect.Parameter.empty} + p.pop("parents", None) + p.pop("return_output", None) + p.pop("return_tensor", None) + params["localize_peaks_kwargs"][method_name] = p + + params["estimate_motion_kwargs"] = dict() + for method_name, method_class in estimate_motion_methods.items(): + sig = inspect.signature(estimate_motion) + p = {k: v.default for k, v in sig.parameters.items() if k != "self" and v.default != inspect.Parameter.empty} + for k in ("peaks", "peak_locations", "method", "extra_outputs", "verbose", "progress_bar", "margin_um"): + p.pop(k) + + sig = inspect.signature(method_class.run) + p.update( + {k: v.default for k, v in sig.parameters.items() if k != "self" and v.default != inspect.Parameter.empty} + ) + params["estimate_motion_kwargs"][method_name] = p + + # no design by subclass + params["interpolate_motion_kwargs"] = dict() + + return params + + +def get_motion_presets(): + preset_keys = list(motion_options_preset.keys()) + preset_keys.remove("") + return preset_keys + + +def get_motion_parameters_preset(preset): + """ + Get the parameters tree for a given preset for motion correction. + """ + preset_params = copy.deepcopy(motion_options_preset[preset]) + all_default_params = _get_default_motion_params() + params = dict() + for step, step_params in preset_params.items(): + if isinstance(step_params, str): + # the doc key + params[step] = step_params + + elif len(step_params) == 0: + # empty dict with no methods = skip the step (select_peaks for instance) + params[step] = dict() + + elif isinstance(step_params, dict): + if "method" in step_params: + method = step_params["method"] + params[step] = all_default_params[step][method] + else: + params[step] = dict() + params[step].update(step_params) + else: + raise ValueError(f"Preset {preset} is wrong") + + return params + + def correct_motion( recording, - preset="nonrigid_accurate", + preset="dredge_fast", folder=None, output_motion=False, output_motion_info=False, @@ -318,6 +363,7 @@ def correct_motion( job_kwargs = fix_job_kwargs(job_kwargs) noise_levels = get_noise_levels(recording, return_scaled=False) + progress_bar = job_kwargs.get("progress_bar", False) if folder is not None: folder = Path(folder) @@ -380,7 +426,7 @@ def correct_motion( ) t0 = time.perf_counter() - motion = estimate_motion(recording, peaks, peak_locations, **estimate_motion_kwargs) + motion = estimate_motion(recording, peaks, peak_locations, progress_bar=progress_bar, **estimate_motion_kwargs) t1 = time.perf_counter() run_times["estimate_motion"] = t1 - t0 diff --git a/src/spikeinterface/preprocessing/tests/test_motion.py b/src/spikeinterface/preprocessing/tests/test_motion.py index a1ad3766a9..e37d947abc 100644 --- a/src/spikeinterface/preprocessing/tests/test_motion.py +++ b/src/spikeinterface/preprocessing/tests/test_motion.py @@ -1,7 +1,13 @@ import shutil from spikeinterface.core import generate_recording -from spikeinterface.preprocessing import correct_motion, load_motion_info, save_motion_info +from spikeinterface.preprocessing import ( + correct_motion, + load_motion_info, + save_motion_info, + get_motion_parameters_preset, +) +from spikeinterface.preprocessing.motion import _get_default_motion_params def test_estimate_and_correct_motion(create_cache_folder): @@ -27,6 +33,19 @@ def test_estimate_and_correct_motion(create_cache_folder): assert motion_info_loaded["motion"] == motion_info["motion"] +def test_get_motion_parameters_preset(): + from pprint import pprint + + p = _get_default_motion_params() + # pprint(p) + + params = get_motion_parameters_preset("nonrigid_accurate") + params = get_motion_parameters_preset("dredge") + params = get_motion_parameters_preset("rigid_fast") + pprint(params) + + if __name__ == "__main__": # print(correct_motion.__doc__) - test_estimate_and_correct_motion() + # test_estimate_and_correct_motion() + test_get_motion_parameters_preset() diff --git a/src/spikeinterface/sortingcomponents/motion/decentralized.py b/src/spikeinterface/sortingcomponents/motion/decentralized.py index 41b03b1c43..a6bb9a5145 100644 --- a/src/spikeinterface/sortingcomponents/motion/decentralized.py +++ b/src/spikeinterface/sortingcomponents/motion/decentralized.py @@ -72,7 +72,7 @@ class DecentralizedRegistration: When not None the parwise discplament matrix is computed in a small time horizon. In short only pair of bins close in time. So the pariwaise matrix is super sparse and have values only the diagonal. - convergence_method: "lsmr" | "lsqr_robust" | "gradient_descent", default: "lsqr_robust" + convergence_method: "lsmr" | "lsqr_robust" | "gradient_descent", default: "lsmr" Which method to use to compute the global displacement vector from the pairwise matrix. robust_regression_sigma: float Use for convergence_method="lsqr_robust" for iterative selection of the regression. @@ -108,9 +108,9 @@ def run( verbose, progress_bar, extra, - bin_um=1.0, + bin_um=5.0, hist_margin_um=20.0, - bin_s=1.0, + bin_s=2.0, histogram_depth_smooth_um=1.0, histogram_time_smooth_s=1.0, pairwise_displacement_method="conv", @@ -122,7 +122,7 @@ def run( batch_size=1, corr_threshold=0.0, time_horizon_s=None, - convergence_method="lsqr_robust", + convergence_method="lsmr", soft_weights=False, normalized_xcorr=True, centered_xcorr=True, @@ -183,7 +183,7 @@ def run( motion_array = np.zeros((temporal_bins.size, len(non_rigid_windows)), dtype=np.float64) windows_iter = non_rigid_windows if progress_bar: - windows_iter = tqdm(windows_iter, desc="windows") + windows_iter = tqdm(windows_iter, desc="pairwise displacement") if spatial_prior: all_pairwise_displacements = np.empty( (len(non_rigid_windows), temporal_bins.size, temporal_bins.size), dtype=np.float64 @@ -299,7 +299,7 @@ def compute_pairwise_displacement( method="conv", weight_scale="linear", error_sigma=0.2, - conv_engine="numpy", + conv_engine=None, torch_device=None, batch_size=1, max_displacement_um=1500, @@ -741,7 +741,10 @@ def jac(p): # corr : tensor # """ # if conv_engine == "torch": -# assert HAVE_TORCH +# import torch +# import torch.nn.functional as F + +# # assert HAVE_TORCH # conv1d = F.conv1d # npx = torch # elif conv_engine == "numpy": diff --git a/src/spikeinterface/sortingcomponents/motion/dredge.py b/src/spikeinterface/sortingcomponents/motion/dredge.py index a0dde6d52b..6cc3a8d8d0 100644 --- a/src/spikeinterface/sortingcomponents/motion/dredge.py +++ b/src/spikeinterface/sortingcomponents/motion/dredge.py @@ -108,6 +108,11 @@ def run( **method_kwargs, ): + try: + import torch + except ImportError: + raise ImportError("The dredge method require torch: pip install torch") + outs = dredge_ap( recording, peaks, diff --git a/src/spikeinterface/sortingcomponents/motion/motion_estimation.py b/src/spikeinterface/sortingcomponents/motion/motion_estimation.py index 2d8564fc54..0d425c98da 100644 --- a/src/spikeinterface/sortingcomponents/motion/motion_estimation.py +++ b/src/spikeinterface/sortingcomponents/motion/motion_estimation.py @@ -21,8 +21,8 @@ def estimate_motion( direction="y", rigid=False, win_shape="gaussian", - win_step_um=50.0, # @alessio charlie is proposing here instead 400 - win_scale_um=150.0, # @alessio charlie is proposing here instead 400 + win_step_um=200.0, + win_scale_um=300.0, win_margin_um=None, method="decentralized", extra_outputs=False, diff --git a/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py b/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py index 0726ca5a87..c05109aaca 100644 --- a/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py +++ b/src/spikeinterface/sortingcomponents/motion/tests/test_motion_estimation.py @@ -160,6 +160,8 @@ def test_estimate_motion(dataset): bin_um=10.0, margin_um=5, extra_outputs=True, + win_step_um=100.0, + win_scale_um=100.0, ) kwargs.update(cases_kwargs) diff --git a/src/spikeinterface/sortingcomponents/peak_detection.py b/src/spikeinterface/sortingcomponents/peak_detection.py index 0d5c92ff28..b984853123 100644 --- a/src/spikeinterface/sortingcomponents/peak_detection.py +++ b/src/spikeinterface/sortingcomponents/peak_detection.py @@ -50,7 +50,7 @@ def detect_peaks( - recording, method="by_channel", pipeline_nodes=None, gather_mode="memory", folder=None, names=None, **kwargs + recording, method="locally_exclusive", pipeline_nodes=None, gather_mode="memory", folder=None, names=None, **kwargs ): """Peak detection based on threshold crossing in term of k x MAD. diff --git a/src/spikeinterface/widgets/tests/test_widgets.py b/src/spikeinterface/widgets/tests/test_widgets.py index a09304dc86..e06c79ad2f 100644 --- a/src/spikeinterface/widgets/tests/test_widgets.py +++ b/src/spikeinterface/widgets/tests/test_widgets.py @@ -57,7 +57,12 @@ def setUpClass(cls): cls.sorting = sorting # estimate motion for motion widgets - _, cls.motion_info = correct_motion(recording, preset="kilosort_like", output_motion_info=True) + _, cls.motion_info = correct_motion( + recording, + preset="kilosort_like", + output_motion_info=True, + estimate_motion_kwargs={"win_step_um": 50, "win_scale_um": 100}, + ) cls.num_units = len(cls.sorting.get_unit_ids())