SpikeInterface / spikeinterface

A Python-based module for creating flexible and robust spike sorting pipelines.
https://spikeinterface.readthedocs.io
MIT License
521 stars 186 forks source link

"Out of range float values are not JSON compliant" error with si.plot_sorting_summary #3508

Open laurenostrowski opened 5 days ago

laurenostrowski commented 5 days ago

Hello,

I've been using si.plot_sorting_summary (spikeinterface version 0.101.0) to visualize and curate the outputs of Kilosort in a web browser. I occasionally get this error "Out of range float values are not JSON compliant" when trying to process some sorts --

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[16], line 3
      1 unit_table_properties = ['quality_labels','KSLabel','isi_violations_ratio','snr','num_spikes']
      2 label_choices = ['sua_1','sua_2','sua_3','mua_4','noise']
----> 3 pss = si.plot_sorting_summary(analyzer, curation=True, backend='sortingview',
      4                               unit_table_properties=unit_table_properties, label_choices=label_choices)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/spikeinterface/widgets/sorting_summary.py:83, in SortingSummaryWidget.__init__(self, sorting_analyzer, unit_ids, sparsity, max_amplitudes_per_unit, min_similarity_for_correlograms, curation, unit_table_properties, label_choices, backend, **backend_kwargs)
     70     unit_ids = sorting.get_unit_ids()
     72 plot_data = dict(
     73     sorting_analyzer=sorting_analyzer,
     74     unit_ids=unit_ids,
   (...)
     80     max_amplitudes_per_unit=max_amplitudes_per_unit,
     81 )
---> 83 BaseWidget.__init__(self, plot_data, backend=backend, **backend_kwargs)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/spikeinterface/widgets/base.py:87, in BaseWidget.__init__(self, data_plot, backend, immediate_plot, **backend_kwargs)
     84 self.backend_kwargs = backend_kwargs_
     86 if immediate_plot:
---> 87     self.do_plot()

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/spikeinterface/widgets/base.py:108, in BaseWidget.do_plot(self)
    106 def do_plot(self):
    107     func = getattr(self, f"plot_{self.backend}")
--> 108     func(self.data_plot, **self.backend_kwargs)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/spikeinterface/widgets/sorting_summary.py:183, in SortingSummaryWidget.plot_sortingview(self, data_plot, **backend_kwargs)
    180 # assemble layout
    181 self.view = vv.Splitter(direction="horizontal", item1=vv.LayoutItem(v1), item2=vv.LayoutItem(v2))
--> 183 self.url = handle_display_and_url(self, self.view, **backend_kwargs)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/spikeinterface/widgets/utils_sortingview.py:42, in handle_display_and_url(widget, view, **backend_kwargs)
     39     if figlabel is None:
     40         # figlabel = widget.default_label
     41         figlabel = ""
---> 42     url = view.url(label=figlabel)
     43     print(url)
     45 return url

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/sortingview/views/View.py:101, in View.url(self, label, state, allow_float64)
    100 def url(self, *, label: str, state: Union[dict, None] = None, allow_float64: bool = False):
--> 101     return fig.url_from_url_dict(self.url_dict(label=label, state=state, allow_float64=allow_float64))

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/sortingview/views/View.py:81, in View.url_dict(self, label, state, allow_float64)
     76 for i, vv in enumerate(all_views):
     77     vv.set_id(f"{i}")
     78 data = {
     79     "type": "MainLayout",
     80     "layout": self.to_dict(),
---> 81     "views": [
     82         {"type": view.type, "viewId": view.id, "dataUri": _upload_data_and_return_uri(view.to_dict(), allow_float64=allow_float64)}
     83         for view in all_views
     84         if not view.is_layout
     85     ],
     86 }
     87 view_url = sortingview_view_url
     88 F = fig.Figure(view_url=view_url, data=data, allow_float64=allow_float64)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/sortingview/views/View.py:82, in <listcomp>(.0)
     76 for i, vv in enumerate(all_views):
     77     vv.set_id(f"{i}")
     78 data = {
     79     "type": "MainLayout",
     80     "layout": self.to_dict(),
     81     "views": [
---> 82         {"type": view.type, "viewId": view.id, "dataUri": _upload_data_and_return_uri(view.to_dict(), allow_float64=allow_float64)}
     83         for view in all_views
     84         if not view.is_layout
     85     ],
     86 }
     87 view_url = sortingview_view_url
     88 F = fig.Figure(view_url=view_url, data=data, allow_float64=allow_float64)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/sortingview/views/View.py:153, in _upload_data_and_return_uri(data, local, allow_float64)
    152 def _upload_data_and_return_uri(data, *, local: bool = False, allow_float64: bool = False):
--> 153     return kcl.store_json(fig.serialize_data(data, allow_float64=allow_float64), local=local)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/kachery_cloud/core.py:18, in store_json(x, separators, indent, label, cache_locally, local)
     16 def store_json(x: Any, *, separators=(',', ':'), indent=None, label: Union[str, None]=None, cache_locally: bool=False, local: bool=False) -> str:
     17     import simplejson
---> 18     text = simplejson.dumps(x, separators=separators, indent=indent, allow_nan=False, sort_keys=True)
     19     return store_text(text, label=label, cache_locally=cache_locally, local=local)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/simplejson/__init__.py:381, in dumps(obj, skipkeys, ensure_ascii, check_circular, allow_nan, cls, indent, separators, encoding, default, use_decimal, namedtuple_as_object, tuple_as_array, bigint_as_string, sort_keys, item_sort_key, for_json, ignore_nan, int_as_string_bitcount, iterable_as_array, **kw)
    379 if cls is None:
    380     cls = JSONEncoder
--> 381 return cls(
    382     skipkeys=skipkeys, ensure_ascii=ensure_ascii,
    383     check_circular=check_circular, allow_nan=allow_nan, indent=indent,
    384     separators=separators, encoding=encoding, default=default,
    385     use_decimal=use_decimal,
    386     namedtuple_as_object=namedtuple_as_object,
    387     tuple_as_array=tuple_as_array,
    388     iterable_as_array=iterable_as_array,
    389     bigint_as_string=bigint_as_string,
    390     sort_keys=sort_keys,
    391     item_sort_key=item_sort_key,
    392     for_json=for_json,
    393     ignore_nan=ignore_nan,
    394     int_as_string_bitcount=int_as_string_bitcount,
    395     **kw).encode(obj)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/simplejson/encoder.py:298, in JSONEncoder.encode(self, o)
    294         return encode_basestring(o)
    295 # This doesn't pass the iterator directly to ''.join() because the
    296 # exceptions aren't as detailed.  The list call should be roughly
    297 # equivalent to the PySequence_Fast that ''.join() would do.
--> 298 chunks = self.iterencode(o)
    299 if not isinstance(chunks, (list, tuple)):
    300     chunks = list(chunks)

File /mnt/cube/lo/envs/spikeproc101/lib/python3.8/site-packages/simplejson/encoder.py:379, in JSONEncoder.iterencode(self, o)
    370     _iterencode = _make_iterencode(
    371         markers, self.default, _encoder, self.indent, floatstr,
    372         self.key_separator, self.item_separator, self.sort_keys,
   (...)
    376         self.item_sort_key, self.encoding, self.for_json,
    377         self.iterable_as_array, Decimal=decimal.Decimal)
    378 try:
--> 379     return _iterencode(o, 0)
    380 finally:
    381     key_memo.clear()

ValueError: Out of range float values are not JSON compliant
zm711 commented 3 days ago

@laurenostrowski hi!

what version are you using? I think we fixed this on main :)

laurenostrowski commented 2 days ago

I'm using version 0.101.0

If useful, a little more debugging on my end revealed that it was 'snr' in unit_table_properties that was throwing the error -- using all quality metrics other than SNR allowed the code to run