Repository: jupyrdf/ipyforcegraph (language: python)

Issue:
Expose nodeLabel API
## Elevator Pitch

Be able to show labels with the `nodeLabel` feature.

## Design Ideas

Add a new `Behavior` subclass that shows labels. 

Explore whether this makes sense in `metadata`, or as a separate ndarray, or something else entirely.
Adding custom node index column
For @nrbgt 's consideration, not offended if we throw this away, just some thoughts.

# Changes
 - [x] Added a way to set the identifier column for the `nodes` 
 - [x] Replaced the `disco ball` emoji with the `crystal ball` 🔮 one (the disco one does not seem to render, at least on Windows/Firefox)
 - [x] make `nblint` ignore notebooks with `untitled` in the name (case insensitive)
 - [x] fixed the `_index.ipynb` to use the new `DataFrameSource`
 - [x] fixed the typing of the `behaviors` in the `ForceGraphs` from `list` to `tuple`
Adding custom node index column
For @nrbgt 's consideration, not offended if we throw this away, just some thoughts.

# Changes
 - [x] Added a way to set the identifier column for the `nodes` 
 - [x] Replaced the `disco ball` emoji with the `crystal ball` 🔮 one (the disco one does not seem to render, at least on Windows/Firefox)
 - [x] make `nblint` ignore notebooks with `untitled` in the name (case insensitive)
 - [x] fixed the `_index.ipynb` to use the new `DataFrameSource`
 - [x] fixed the typing of the `behaviors` in the `ForceGraphs` from `list` to `tuple`


Discussion / hints:

Fix patch:
diff --git a/.binder/environment.yml b/.binder/environment.yml
index 25294074..6057e2aa 100644
--- a/.binder/environment.yml
+++ b/.binder/environment.yml
@@ -13,7 +13,6 @@ dependencies:
   - git
   - hypothesis
   - importnb
-  - ipydatawidgets
   - ipython >=7
   - ipywidgets >=8.0.4,<9
   - isort
@@ -26,6 +25,8 @@ dependencies:
   - myst-nb
   - networkx
   - nodejs >=18,<19
+  - numcodecs
+  - orjson
   - packaging >=22.0
   - pandas
   - pydata-sphinx-theme
@@ -46,6 +47,7 @@ dependencies:
   - sphinx-autobuild
   - sphinx-autodoc-typehints
   - tomli
+  - traittypes
   - twine
   - wheel
   # lite
@@ -54,4 +56,4 @@ dependencies:
   - python >=3.8,<3.12.0a0
   # this is handled out-of-band
   # - pip:
-  #   - jupyterlite ==0.1.0b16
+  #   - jupyterlite ==0.1.0b17
diff --git a/.binder/postBuild b/.binder/postBuild
index da16d6cb..f3f48f8f 100755
--- a/.binder/postBuild
+++ b/.binder/postBuild
@@ -1,6 +1,6 @@
 #!/usr/bin/env python3
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import os
diff --git a/.github/lock-environment.yml b/.github/lock-environment.yml
index d058d1a0..5a29deca 100644
--- a/.github/lock-environment.yml
+++ b/.github/lock-environment.yml
@@ -3,6 +3,7 @@ channels:
   - nodefaults
 
 dependencies:
-  - conda-lock >=1.2,<1.3
+  - conda-lock >=1.3,<1.4
   - mamba >=1.1.0,<1.2
   - python >=3.11,<3.12
+  - conda !=22.11.1
diff --git a/.github/locks/linux-64_3.11_environment.conda.lock b/.github/locks/linux-64_3.11_environment.conda.lock
index bbd060f5..274d0a46 100644
--- a/.github/locks/linux-64_3.11_environment.conda.lock
+++ b/.github/locks/linux-64_3.11_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.11,<3.12
 # dependencies:
@@ -103,7 +105,7 @@ https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161
 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae
 https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b
 https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1
-https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hff17c54_1.tar.bz2#2b7dbfa6988a41f9d23ba6d4f0e1d74e
+https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.51.0-hff17c54_0.conda#dd682f0b6d65e75b2bc868fc8e93d87e
 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f
 https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8
@@ -123,7 +125,6 @@ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz
 https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openblas.tar.bz2#955d993f41f9354bf753d29864ea20ad
 https://conda.anaconda.org/conda-forge/linux-64/nodejs-18.12.1-h8839609_0.tar.bz2#305f25b78340b0f7b391a6919d1246f2
 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-ha86cf86_0_cpython.tar.bz2#531b2b97ce96cc95a587bdf7c74e31c0
-https://conda.anaconda.org/conda-forge/noarch/_ipython_minor_entry_point-8.7.0-h0c17e10_0.conda#8a63fb4d63db7b245ecf3c6f907935ff
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
@@ -165,19 +166,20 @@ https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py311hd4cff14_2
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.4-py311h4dd048b_1.tar.bz2#bead0c840170e53af42618434617ea45
 https://conda.anaconda.org/conda-forge/linux-64/mypy_extensions-0.4.3-py311h38be061_6.tar.bz2#6f53e53ab6a2f24299af0e56174777a2
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
 https://conda.anaconda.org/conda-forge/noarch/networkx-2.8.8-pyhd8ed1ab_0.tar.bz2#bb45ff9deddb045331fd039949f39650
-https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.0-py311hbde0eaa_0.conda#a557423cfc6da0f693127b4886fb8d6d
+https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.1-py311hbde0eaa_0.conda#236dda53b49b70717d7280efb3494db7
+https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.3-py311h6a9de79_0.conda#3f8a2df7dcfafc582824837853d4e735
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.4-py311hd4cff14_0.tar.bz2#6fbda857a56adb4140bed339fbe0b801
@@ -186,7 +188,7 @@ https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.2-pyhd8ed1ab_0.tar.b
 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pyflakes-3.0.1-pyhd8ed1ab_0.conda#44b7d77d96560c93e0e11437a3c35254
-https://conda.anaconda.org/conda-forge/linux-64/pyrsistent-0.19.2-py311hd4cff14_0.tar.bz2#e6808d85cbd28e4fb2d61294627fa1b1
+https://conda.anaconda.org/conda-forge/linux-64/pyrsistent-0.19.3-py311h2582759_0.conda#e53876b66dcc4ba8a0afa63cd8502ac3
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025
 https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.16.2-pyhd8ed1ab_0.tar.bz2#5fe4b6002f505336734ce92961b3e6a0
 https://conda.anaconda.org/conda-forge/linux-64/python-libarchive-c-4.0-py311h38be061_2.tar.bz2#1c3e2d22ddfb6ff2a0edd60e91e018db
@@ -220,7 +222,7 @@ https://conda.anaconda.org/conda-forge/linux-64/ujson-5.5.0-py311ha362b79_1.tar.
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/linux-64/ansi2html-1.8.0-py311h38be061_1.tar.bz2#5ce42a68e90f54266ad06ac13b773ef1
 https://conda.anaconda.org/conda-forge/noarch/anyio-3.6.1-pyhd8ed1ab_1.tar.bz2#d65ef75084f8adbadb696dfd91148e79
@@ -228,38 +230,37 @@ https://conda.anaconda.org/conda-forge/noarch/asttokens-2.2.1-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba
 https://conda.anaconda.org/conda-forge/noarch/backports.functools_lru_cache-1.6.4-pyhd8ed1ab_0.tar.bz2#c5b3edc62d6309088f4970b3eaaa65a6
 https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.11.1-pyha770c72_0.tar.bz2#eeec8814bd97b2681f708bb127478d7d
-https://conda.anaconda.org/conda-forge/linux-64/black-22.10.0-py311h38be061_2.tar.bz2#c3c459c7ddb8ee0d658ad1d50d6511de
 https://conda.anaconda.org/conda-forge/noarch/bleach-5.0.1-pyhd8ed1ab_0.tar.bz2#1f5151d37e4a2b1137f81c89a3a769f2
 https://conda.anaconda.org/conda-forge/noarch/cattrs-22.2.0-pyhd8ed1ab_0.tar.bz2#5dacf4d924ae284579288e378b1f5943
 https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce
 https://conda.anaconda.org/conda-forge/noarch/comm-0.1.2-pyhd8ed1ab_0.conda#3c78af4752bb1600ebe5e83ef4588eaa
 https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2#6aa0173c14befcd577ded130cf6f22f5
-https://conda.anaconda.org/conda-forge/linux-64/coverage-7.0.0-py311h2582759_0.conda#364edb6f1d7dd090a10c8a7312ade8fe
+https://conda.anaconda.org/conda-forge/linux-64/coverage-7.0.3-py311h2582759_0.conda#869f0ef5a6531e110ad220d3d3ad8e86
 https://conda.anaconda.org/conda-forge/linux-64/curl-7.87.0-hdc1c0ab_0.conda#b14123ca479b9473d7f7395b0fd25c97
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
 https://conda.anaconda.org/conda-forge/noarch/hypothesis-6.61.0-pyha770c72_0.conda#df3897a189f054eaa666a3945fd574ab
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.2.0-pyha770c72_0.conda#2e8eec7a08bcf85547a3778225f00634
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-5.1.0-py311h38be061_0.conda#e3d41c9f46f3928a41bcf2ba6eb2a2ab
 https://conda.anaconda.org/conda-forge/noarch/livereload-2.6.3-pyh9f0ad1d_0.tar.bz2#b7190e3ec3eff52839434bf4698e2d62
 https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-2.1.0-pyhd8ed1ab_0.tar.bz2#d821ebc1ebe21d4cac2555278c2cd970
 https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.6-pyhd8ed1ab_0.tar.bz2#b21613793fcc81d944c76c9f2864a7de
 https://conda.anaconda.org/conda-forge/linux-64/mypy-0.991-py311hd4cff14_0.tar.bz2#0255dd3a667b3500039a496ffd27d474
+https://conda.anaconda.org/conda-forge/linux-64/numcodecs-0.11.0-py311hcafe171_1.conda#ecdaf0772e524ed51218f6d52ef74424
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2#330448ce4403cc74990ac07c555942a1
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.0-pyhd8ed1ab_2.tar.bz2#ac82c7aebc282e6ac0450fca012ca78c
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
 https://conda.anaconda.org/conda-forge/noarch/robotframework-robocop-1.12.0-pyhd8ed1ab_0.tar.bz2#37e6dad59a24e6d7ff64a533c4135f57
 https://conda.anaconda.org/conda-forge/noarch/robotframework-stacktrace-0.4.1-pyhd8ed1ab_0.tar.bz2#3dc788e294fd159537c931dbb964511e
-https://conda.anaconda.org/conda-forge/linux-64/sqlalchemy-1.4.45-py311h2582759_0.conda#c8452b47661df1285d72803934abc594
+https://conda.anaconda.org/conda-forge/linux-64/sqlalchemy-1.4.46-py311h2582759_0.conda#3030087ba2101543b8b82e2832a70063
 https://conda.anaconda.org/conda-forge/noarch/terminado-0.17.1-pyh41d4057_0.conda#3788984d535770cad699efaeb6cb3037
 https://conda.anaconda.org/conda-forge/noarch/tinycss2-1.2.1-pyhd8ed1ab_0.tar.bz2#7234c9eefff659501cd2fe0d2ede4d48
 https://conda.anaconda.org/conda-forge/noarch/traittypes-0.2.1-pyh9f0ad1d_2.tar.bz2#7d32ccb5334a6822c28af3e864550618
@@ -268,68 +269,70 @@ https://conda.anaconda.org/conda-forge/noarch/url-normalize-1.4.3-pyhd8ed1ab_0.t
 https://conda.anaconda.org/conda-forge/linux-64/argon2-cffi-bindings-21.2.0-py311hd4cff14_3.tar.bz2#5159e874f65ac382773d2b534a1d7b80
 https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py311hd4cff14_1005.tar.bz2#9bdac7084ecfc08338bae1b976535724
 https://conda.anaconda.org/conda-forge/linux-64/cmarkgfm-0.8.0-py311hd4cff14_2.tar.bz2#ed1a2dba3b53fcd450f2fe867af0ba3f
-https://conda.anaconda.org/conda-forge/linux-64/cryptography-38.0.4-py311h42a1071_0.conda#34c95722eb879d7a9ee0546671084b2d
+https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py311h9b4c7bb_0.conda#74eed5e75574839f1ae7a7048f529a66
 https://conda.anaconda.org/conda-forge/noarch/doit-0.36.0-pyhd8ed1ab_0.tar.bz2#fc5e53d070f1ee7bb38c2ece282dcb82
 https://conda.anaconda.org/conda-forge/linux-64/git-2.39.0-pl5321h693f4a3_0.conda#d52d166cf45275bdc6c108f951371d37
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.2.0-hd8ed1ab_0.conda#fe869d480dad3299a8ac60f31fb10bbd
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
-https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1ab_0.tar.bz2#243f63592c8e449f40cd42eb5cf32f40
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
 https://conda.anaconda.org/conda-forge/linux-64/pandas-1.5.2-py311h8b32b4d_0.conda#d203d6938a0c1a76cb540a2972644af7
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytest-asyncio-0.20.3-pyhd8ed1ab_0.conda#aa462bf71d7b327dcc00ae523f8923ef
 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7
 https://conda.anaconda.org/conda-forge/noarch/pytest-metadata-2.0.4-pyhd8ed1ab_0.tar.bz2#7ac02a65917993d38ca1bfd7b87208e4
 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.1.0-pyhd8ed1ab_0.conda#e82f8fb903d7c4a59c77954759c341f9
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.2-pyhd8ed1ab_0.conda#e7df0fdd404616638df5ece6e69ba7af
 https://conda.anaconda.org/conda-forge/linux-64/trio-0.22.0-py311h38be061_1.tar.bz2#0564e63c41c0527f8085a572a931f1e6
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
 https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2#00ba804b54f451d102f6a7615f08470d
 https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-21.3.0-pyhd8ed1ab_0.tar.bz2#a0b402db58f73aaab8ee0ca1025a362e
-https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
+https://conda.anaconda.org/conda-forge/linux-64/black-22.10.0-py311h38be061_2.tar.bz2#c3c459c7ddb8ee0d658ad1d50d6511de
+https://conda.anaconda.org/conda-forge/linux-64/jupyter_core-5.1.2-py311h38be061_0.conda#43fd842b1add2030e8958ea79e9bf1cc
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
 https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py311h38be061_1.tar.bz2#ec745aaae03cc47120c1f11ac7b7bcf5
 https://conda.anaconda.org/conda-forge/noarch/trio-websocket-0.9.2-pyhd8ed1ab_0.tar.bz2#7acf3fc982eef23b24aed10e80d5dc99
-https://conda.anaconda.org/conda-forge/noarch/ipython-8.7.0-pyh41d4057_0.conda#adc2f96edf35423c091dba93b642573a
+https://conda.anaconda.org/conda-forge/noarch/ipython-8.8.0-pyh41d4057_0.conda#788c234d910ad9f37174d1845c1a52c7
+https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
 https://conda.anaconda.org/conda-forge/linux-64/keyring-23.13.1-py311h38be061_0.conda#0dc0127b1daefefa5e2caa49dde5c230
-https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
+https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
 https://conda.anaconda.org/conda-forge/noarch/robotframework-tidy-3.3.2-pyhd8ed1ab_0.tar.bz2#354a5c374999c2688332c073e2450951
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-22.10.0-hd8ed1ab_2.tar.bz2#80112c21a14035fe1d786f082ce27978
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.19.4-pyh210e3f2_0.conda#65372b6dd819e2c36345cf91eeb4ff06
-https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
+https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
 https://conda.anaconda.org/conda-forge/noarch/selenium-4.7.2-pyhd8ed1ab_0.conda#4f6238a5e80996ee0bbee28b487aada5
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
-https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
+https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-0.9.7-pyhd8ed1ab_0.conda#399c98b39eb6bdc4b1d40b7611a6d384
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1ab_0.tar.bz2#a4cd20af9711434f89d1ec0d2b3ae6ba
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
-https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.12.0-pyhd8ed1ab_0.tar.bz2#fe4a16a5ffc6ff74d4a479a44f6bf6a2
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-pyhd8ed1ab_0.tar.bz2#9204ee150d1e42f4c995376a8adff03c
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
+https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/linux-64_3.7_environment.conda.lock b/.github/locks/linux-64_3.7_environment.conda.lock
index d47c3b8a..76a8c857 100644
--- a/.github/locks/linux-64_3.7_environment.conda.lock
+++ b/.github/locks/linux-64_3.7_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.7,<3.8
 # dependencies:
@@ -112,7 +114,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libblas-3.9.0-16_linux64_openbla
 https://conda.anaconda.org/conda-forge/linux-64/libbrotlidec-1.0.9-h166bdaf_8.tar.bz2#4ae4d7795d33e02bd20f6b23d91caf82
 https://conda.anaconda.org/conda-forge/linux-64/libbrotlienc-1.0.9-h166bdaf_8.tar.bz2#04bac51ba35ea023dc48af73c1c88c25
 https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1
-https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hff17c54_1.tar.bz2#2b7dbfa6988a41f9d23ba6d4f0e1d74e
+https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.51.0-hff17c54_0.conda#dd682f0b6d65e75b2bc868fc8e93d87e
 https://conda.anaconda.org/conda-forge/linux-64/libpng-1.6.39-h753d276_0.conda#e1c890aebdebbfbf87e2c917187b4416
 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f
 https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906
@@ -181,20 +183,21 @@ https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py37h540881e_1.
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.4-py37h7cecad7_0.tar.bz2#2da951801472ad558471831f9cee2bae
 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19
 https://conda.anaconda.org/conda-forge/linux-64/mypy_extensions-0.4.3-py37h89c1867_5.tar.bz2#124acd9a71204cea178759842120608b
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.21.6-py37h976b520_0.tar.bz2#b0701d8dc4849b6e06caf1c84135c13c
+https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.1-py37h540881e_0.tar.bz2#4207234c6822359b587813c471a77c88
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
 https://conda.anaconda.org/conda-forge/linux-64/pillow-9.2.0-py37h850a105_2.tar.bz2#9532a440710f0245e79070561762e138
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/linux-64/psutil-5.9.3-py37h540881e_0.tar.bz2#0c813ad118e926df328bf74899a48047
 https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2#359eeb6536da0e687af562ed265ec263
@@ -239,7 +242,7 @@ https://conda.anaconda.org/conda-forge/linux-64/unicodedata2-14.0.0-py37h540881e
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/noarch/anyio-3.6.2-pyhd8ed1ab_0.tar.bz2#8ada050fa88f26916fc1e76e368a49fd
 https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba
@@ -257,7 +260,7 @@ https://conda.anaconda.org/conda-forge/linux-64/git-2.39.0-pl5321h693f4a3_0.cond
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
 https://conda.anaconda.org/conda-forge/linux-64/importlib-metadata-4.11.4-py37h89c1867_0.tar.bz2#71107630527e4bd82932952351231efe
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
@@ -270,7 +273,7 @@ https://conda.anaconda.org/conda-forge/linux-64/mypy-0.982-py37h540881e_0.tar.bz
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2#330448ce4403cc74990ac07c555942a1
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
 https://conda.anaconda.org/conda-forge/noarch/robotframework-robocop-1.12.0-pyhd8ed1ab_0.tar.bz2#37e6dad59a24e6d7ff64a533c4135f57
@@ -293,10 +296,12 @@ https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1ab_0.tar.bz2#243f63592c8e449f40cd42eb5cf32f40
 https://conda.anaconda.org/conda-forge/linux-64/kiwisolver-1.4.4-py37h7cecad7_0.tar.bz2#997912aa3ebab21640e3ba5ec168353d
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
+https://conda.anaconda.org/conda-forge/linux-64/numcodecs-0.10.2-py37hd23a5d3_0.tar.bz2#a1780a22c5e769803dc5443d4a3cdcf8
 https://conda.anaconda.org/conda-forge/linux-64/pandas-1.3.5-py37he8f5f7f_0.tar.bz2#6ebf1968b199a141a5cce6adaedb3651
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/linux-64/sqlalchemy-1.4.42-py37h540881e_0.tar.bz2#921bb310665fba1ed0f64f3287fda6d4
 https://conda.anaconda.org/conda-forge/linux-64/trio-0.21.0-py37h89c1867_0.tar.bz2#6ed8b58c9866953a5139eb501e6756ae
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
@@ -308,7 +313,7 @@ https://conda.anaconda.org/conda-forge/linux-64/matplotlib-base-3.5.3-py37hf395d
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
 https://conda.anaconda.org/conda-forge/linux-64/pluggy-1.0.0-py37h89c1867_3.tar.bz2#6364b39df084274961ed1d21a8cd060b
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
@@ -341,8 +346,7 @@ https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1a
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
 https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
@@ -352,7 +356,7 @@ https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-py
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/linux-64_lock-environment.conda.lock b/.github/locks/linux-64_lock-environment.conda.lock
index 6a6a99b9..3bd87d39 100644
--- a/.github/locks/linux-64_lock-environment.conda.lock
+++ b/.github/locks/linux-64_lock-environment.conda.lock
@@ -3,14 +3,15 @@
 #   - nodefaults
 
 # dependencies:
-#   - conda-lock >=1.2,<1.3
+#   - conda-lock >=1.3,<1.4
 #   - mamba >=1.1.0,<1.2
 #   - python >=3.11,<3.12
+#   - conda !=22.11.1
 # dependencies: []
 
 @EXPLICIT
 https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81
-https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.9.24-ha878542_0.tar.bz2#41e4e87062433e283696cf384f952ef6
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2022.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.39-hcc3a1bd_1.conda#737be0d34c22d24432049ab7a3214de4
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
 https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-4-hd8ed1ab_3.tar.bz2#878f923dd6acc8aeb47a75da6c4098be
@@ -36,87 +37,89 @@ https://conda.anaconda.org/conda-forge/linux-64/lz4-c-1.9.3-h9c3ff4c_1.tar.bz2#f
 https://conda.anaconda.org/conda-forge/linux-64/lzo-2.10-h516909a_1000.tar.bz2#bb14fcb13341b81d5eb386423b9d2bac
 https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.3-h27087fc_1.tar.bz2#4acfc691e64342b9dae57cf2adc63238
 https://conda.anaconda.org/conda-forge/linux-64/openssl-3.0.7-h0b41bf4_1.conda#7adaac6ff98219bcb99b45e408b80f4e
-https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.3-h7f98852_0.tar.bz2#1e16d4142b016b6a5ebdeb3d6d33aaf4
+https://conda.anaconda.org/conda-forge/linux-64/reproc-14.2.4-h0b41bf4_0.conda#0f51393e019df1f0047ef864cd9ddeec
 https://conda.anaconda.org/conda-forge/linux-64/xz-5.2.6-h166bdaf_0.tar.bz2#2161070d867d1b1204ea749c8eec4ef0
 https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h7f98852_2.tar.bz2#4cb3ad778ec2d5a7acbdf254eb1c42ae
 https://conda.anaconda.org/conda-forge/linux-64/yaml-cpp-0.7.0-h27087fc_2.tar.bz2#0449d47d8457feaa3720d4779616dde2
 https://conda.anaconda.org/conda-forge/linux-64/libedit-3.1.20191231-he28a2e2_2.tar.bz2#4d331e44109e3f0e19b4cb8f9b82f3e1
-https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.47.0-hff17c54_1.tar.bz2#2b7dbfa6988a41f9d23ba6d4f0e1d74e
-https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.22-h6239696_0.tar.bz2#461963bb499e58bae159a898600f8792
+https://conda.anaconda.org/conda-forge/linux-64/libnghttp2-1.51.0-hff17c54_0.conda#dd682f0b6d65e75b2bc868fc8e93d87e
+https://conda.anaconda.org/conda-forge/linux-64/libsolv-0.7.23-h3eb15da_0.conda#122332e6deb4aea9eaf22021d2ecd256
 https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_0.tar.bz2#2e5f9a37d487e1019fd4d8113adb2f9f
 https://conda.anaconda.org/conda-forge/linux-64/libssh2-1.10.0-hf14f497_3.tar.bz2#d85acad4b47dff4e3def14a769a97906
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.3-h7463322_0.tar.bz2#3b933ea47ef8f330c4c068af25fcd6a8
 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b
 https://conda.anaconda.org/conda-forge/linux-64/readline-8.1.2-h0f457ee_0.tar.bz2#db2ebbe2943aae81ed051a6a9af8e0fa
-https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.3-h9c3ff4c_0.tar.bz2#1fc15d3b393b62192d3eeade92b61610
+https://conda.anaconda.org/conda-forge/linux-64/reproc-cpp-14.2.4-hcb278e6_0.conda#ede8e0f849f2fee2f78cb488b4ea3b33
 https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.12-h27826a3_0.tar.bz2#5b8c42eb62e9fc961af70bdd6a26e168
 https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.2-h6239696_4.tar.bz2#adcf0be7897e73e312bd24353b613f74
-https://conda.anaconda.org/conda-forge/linux-64/krb5-1.19.3-h08a2579_0.tar.bz2#d25e05e7ee0e302b52d24491db4891eb
-https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.5.2-hada088e_3.tar.bz2#c0c3973a9f2df3e1a408e3205d86a88d
+https://conda.anaconda.org/conda-forge/linux-64/krb5-1.20.1-h81ceb04_0.conda#89a41adce7106749573d883b2f657d78
+https://conda.anaconda.org/conda-forge/linux-64/libarchive-3.6.2-h3d51595_0.conda#9f915b4adeb9dcfd450b9ad238e2db4c
 https://conda.anaconda.org/conda-forge/linux-64/libglib-2.74.1-h606061b_1.tar.bz2#ed5349aa96776e00b34eccecf4a948fe
 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.0-ha86cf86_0_cpython.tar.bz2#531b2b97ce96cc95a587bdf7c74e31c0
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/cachy-0.3.0-pyhd8ed1ab_1.tar.bz2#5dfee17f24e2dfd18d7392b48c9351e2
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d
+https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/crashtest-0.3.1-pyhd8ed1ab_0.tar.bz2#b8477552274c1cfdb533e954c76523f1
 https://conda.anaconda.org/conda-forge/linux-64/dbus-1.13.6-h5008d03_3.tar.bz2#ecfff944ba3960ecb334b9a2663d708d
 https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.6-pyhd8ed1ab_0.tar.bz2#b65b4d50dbd2d50fa0aeac367ec9eed7
-https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.2-pyhd8ed1ab_0.conda#0f09c2bc17ddd8732be8e5b99297c7ce
+https://conda.anaconda.org/conda-forge/noarch/filelock-3.9.0-pyhd8ed1ab_0.conda#1addc115923d646ca19ed90edc413506
 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed
 https://conda.anaconda.org/conda-forge/noarch/jeepney-0.8.0-pyhd8ed1ab_0.tar.bz2#9800ad1699b42612478755a2d26c722d
-https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.86.0-h2283fc2_1.tar.bz2#fdca8cd67ec2676f90a70ac73a32538b
+https://conda.anaconda.org/conda-forge/linux-64/libcurl-7.87.0-hdc1c0ab_0.conda#bc302fa1cf8eda15c60f669b7524a320
 https://conda.anaconda.org/conda-forge/linux-64/markupsafe-2.1.1-py311hd4cff14_2.tar.bz2#6b0d96114b4a841630ef7d0dff10d4e8
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
 https://conda.anaconda.org/conda-forge/linux-64/msgpack-python-1.0.4-py311h4dd048b_1.tar.bz2#bead0c840170e53af42618434617ea45
+https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pastel-0.2.1-pyhd8ed1ab_0.tar.bz2#a4eea5bff523f26442405bc5d1f52adb
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/linux-64/pycosat-0.6.4-py311hd4cff14_1.tar.bz2#17399f8b68b4592f098ab18d4fdb0ac4
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pylev-1.4.0-pyhd8ed1ab_0.tar.bz2#edf8651c4379d9d1495ad6229622d150
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025
 https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0-py311hd4cff14_5.tar.bz2#da8769492e423103c59f469f4f17f8d9
 https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml.clib-0.2.7-py311h2582759_1.conda#5e997292429a22ad50c11af0a2cb0f08
 https://conda.anaconda.org/conda-forge/linux-64/ruamel_yaml-0.15.80-py311hd4cff14_1008.tar.bz2#cfc7aa9d4e13c267fb6531d4788f2ede
-https://conda.anaconda.org/conda-forge/noarch/setuptools-65.5.1-pyhd8ed1ab_0.tar.bz2#cfb8dc4d9d285ca5fb1177b9dd450e33
+https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
+https://conda.anaconda.org/conda-forge/noarch/smmap-3.0.5-pyh44b312d_0.tar.bz2#3a8dc70789709aa315325d5df06fb7e4
 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96
 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36
 https://conda.anaconda.org/conda-forge/noarch/typing-3.10.0.0-pyhd8ed1ab_0.tar.bz2#e6573ac68718f17b9d4f5c8eda3190f2
 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
-https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_2.tar.bz2#675a030b42ca1ee616e47ab208c39dff
+https://conda.anaconda.org/conda-forge/linux-64/cffi-1.15.1-py311h409f033_3.conda#9025d0786dbbe4bc91fd8e85502decce
 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.2-pyhd8ed1ab_1.tar.bz2#72a46ffc25701c173932fd55cf0965d3
 https://conda.anaconda.org/conda-forge/noarch/clikit-0.6.2-pyh9f0ad1d_0.tar.bz2#159273f717a11e53b2656f8b6521a5e2
+https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.10-pyhd8ed1ab_0.conda#3706d2f3d7cb5dae600c833345a76132
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.1.0-pyha770c72_0.conda#46a62e35b9ae515cf0e49afc7fe0e7ef
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/linux-64/libmamba-1.1.0-h70b1f8a_2.conda#9d38a1b35b7de29dfc4d64daeb1e27fc
-https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85
+https://conda.anaconda.org/conda-forge/linux-64/libmamba-1.1.0-hde2b089_3.conda#61ae3dd2df8aa569d80db7021c6efed5
 https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.17.21-py311hd4cff14_2.tar.bz2#1e3fa73ad16d9c64e8e3421861a49ec0
 https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.11.6-pyha770c72_0.tar.bz2#471bf9e605820b59988e830382b8d654
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026
-https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.17.0-py311h38be061_0.conda#ca610f1d7a81270145c2630f79b5b7ba
 https://conda.anaconda.org/conda-forge/linux-64/brotlipy-0.7.0-py311hd4cff14_1005.tar.bz2#9bdac7084ecfc08338bae1b976535724
-https://conda.anaconda.org/conda-forge/linux-64/cryptography-38.0.4-py311h42a1071_0.conda#34c95722eb879d7a9ee0546671084b2d
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.1.0-hd8ed1ab_0.conda#3dc2248927de739b4d2e2da9a9972bfe
-https://conda.anaconda.org/conda-forge/linux-64/libmambapy-1.1.0-py311hc072ffd_2.conda#15d7a71d27808365d4b1044183bbf74c
-https://conda.anaconda.org/conda-forge/linux-64/pydantic-1.10.2-py311hd4cff14_1.tar.bz2#96e928fba232d26b60e8bdea1f76f493
+https://conda.anaconda.org/conda-forge/linux-64/cryptography-39.0.0-py311h9b4c7bb_0.conda#74eed5e75574839f1ae7a7048f529a66
+https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.30-pyhd8ed1ab_0.conda#0c217ab2f5ef6925e4e52c70b57cfc4a
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
+https://conda.anaconda.org/conda-forge/linux-64/libmambapy-1.1.0-py311h1f88262_3.conda#70e46c3567528b98e088e8033f4eaad6
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
+https://conda.anaconda.org/conda-forge/linux-64/pydantic-1.10.4-py311h2582759_0.conda#c8f72e2bc6d9ef667a881c0922967c0f
 https://conda.anaconda.org/conda-forge/linux-64/zstandard-0.19.0-py311hbe0fcd7_1.conda#1f48d127dd18240505cba632b67f7931
 https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.7.0-pyhd8ed1ab_1.conda#1a2fa9e53cfbc2e4d9ab21990805a436
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/linux-64/secretstorage-3.3.3-py311h38be061_1.tar.bz2#ec745aaae03cc47120c1f11ac7b7bcf5
+https://conda.anaconda.org/conda-forge/linux-64/virtualenv-20.17.1-py311h38be061_0.conda#46ee18791b2f786c1e052664b3842580
 https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.0.2-pyh38be061_0.conda#44800e9bd13143292097c65e57323038
-https://conda.anaconda.org/conda-forge/linux-64/keyring-23.11.0-py311h38be061_0.tar.bz2#7543c57f42d726a96ba291f072067d0b
+https://conda.anaconda.org/conda-forge/linux-64/keyring-23.13.1-py311h38be061_0.conda#0dc0127b1daefefa5e2caa49dde5c230
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
-https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.12-pyhd8ed1ab_1.tar.bz2#e4b40ac0d53e81ebf8892e3b3ca9c1cf
+https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.11-pyhd8ed1ab_0.tar.bz2#6eefee9888f33f150b5d44d616b1a613
 https://conda.anaconda.org/conda-forge/linux-64/conda-22.9.0-py311h38be061_2.tar.bz2#d083486f8b405adad834ba22b9cd7340
 https://conda.anaconda.org/conda-forge/noarch/ensureconda-1.4.3-pyhd8ed1ab_0.tar.bz2#c99ae3abf501990769047b4b40a98f17
-https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.2.1-pyhd8ed1ab_1.tar.bz2#7b1dde4760c5c554523fead6c2771af2
-https://conda.anaconda.org/conda-forge/linux-64/mamba-1.1.0-py311h3072747_2.conda#d090b2f1b164c9584ad96902d5a09b1d
+https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.3.0-pyhd8ed1ab_0.conda#1165b4b0171fad7555822fe3a85365ed
+https://conda.anaconda.org/conda-forge/linux-64/mamba-1.1.0-py311h3072747_3.conda#c85b085f7d8a20051411c12ae087a03d
diff --git a/.github/locks/osx-64_3.11_environment.conda.lock b/.github/locks/osx-64_3.11_environment.conda.lock
index b86b80f2..e254dd8b 100644
--- a/.github/locks/osx-64_3.11_environment.conda.lock
+++ b/.github/locks/osx-64_3.11_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.11,<3.12
 # dependencies: []
@@ -97,12 +99,11 @@ https://conda.anaconda.org/conda-forge/osx-64/zlib-1.2.13-hfd90126_4.tar.bz2#be9
 https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.2-hfa58983_4.tar.bz2#0b446e84f3ccf085e590dc1f73eebe3f
 https://conda.anaconda.org/conda-forge/osx-64/krb5-1.20.1-h049b76e_0.conda#db11fa2968ef0837288fe2d7f5b77a50
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran-5.0.0-11_3_0_h97931a8_27.conda#7d25335e67256924aa04de681e68e807
-https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.47.0-h5aae05b_1.tar.bz2#19d5ae4be3e4b3cfa5696f3667e8c631
+https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.51.0-he2ab024_0.conda#910e7f012beecf5d845a993feb9259a9
 https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.10.0-h47af595_3.tar.bz2#5a28624eeb7812b585b9e2d75f846ba2
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.3-hb9e07b5_0.tar.bz2#13ba8bf8f44cdac2e5401dac20a36040
 https://conda.anaconda.org/conda-forge/osx-64/nodejs-18.12.1-hd0c9b3c_0.tar.bz2#e5ab86f2155244c022f8db0165bce009
 https://conda.anaconda.org/conda-forge/osx-64/python-3.11.0-h559f36b_0_cpython.tar.bz2#9eac7bb07be3725945c23c4ae90f9faa
-https://conda.anaconda.org/conda-forge/noarch/_ipython_minor_entry_point-8.7.0-h0c17e10_0.conda#8a63fb4d63db7b245ecf3c6f907935ff
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
@@ -144,18 +145,19 @@ https://conda.anaconda.org/conda-forge/osx-64/markupsafe-2.1.1-py311h5547dcb_2.t
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.0.4-py311hd2070f0_1.tar.bz2#e91973b43c03d74de80de087ff46e393
 https://conda.anaconda.org/conda-forge/osx-64/mypy_extensions-0.4.3-py311h6eed73b_6.tar.bz2#0310303443cb3d296e426a1fa3586c1d
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
 https://conda.anaconda.org/conda-forge/noarch/networkx-2.8.8-pyhd8ed1ab_0.tar.bz2#bb45ff9deddb045331fd039949f39650
+https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.3-py311h8b8394e_0.conda#eb2a49e63887c86ef1a49ff70ab3c831
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/osx-64/psutil-5.9.4-py311h5547dcb_0.tar.bz2#7240e0886bb94ea8846cb010352d3dd8
@@ -164,7 +166,7 @@ https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.2-pyhd8ed1ab_0.tar.b
 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pyflakes-3.0.1-pyhd8ed1ab_0.conda#44b7d77d96560c93e0e11437a3c35254
-https://conda.anaconda.org/conda-forge/osx-64/pyrsistent-0.19.2-py311h5547dcb_0.tar.bz2#fbfc67fe80d675ac56a3849f5215dddc
+https://conda.anaconda.org/conda-forge/osx-64/pyrsistent-0.19.3-py311h5547dcb_0.conda#f114c0dab9f9c894b260297371124634
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025
 https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.16.2-pyhd8ed1ab_0.tar.bz2#5fe4b6002f505336734ce92961b3e6a0
 https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689
@@ -197,7 +199,7 @@ https://conda.anaconda.org/conda-forge/osx-64/ujson-5.5.0-py311h814d153_1.tar.bz
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/osx-64/ansi2html-1.8.0-py311h6eed73b_1.tar.bz2#f38cdc0af433fdbe1765af0fefcbb187
 https://conda.anaconda.org/conda-forge/noarch/anyio-3.6.1-pyhd8ed1ab_1.tar.bz2#d65ef75084f8adbadb696dfd91148e79
@@ -205,24 +207,22 @@ https://conda.anaconda.org/conda-forge/noarch/asttokens-2.2.1-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba
 https://conda.anaconda.org/conda-forge/noarch/backports.functools_lru_cache-1.6.4-pyhd8ed1ab_0.tar.bz2#c5b3edc62d6309088f4970b3eaaa65a6
 https://conda.anaconda.org/conda-forge/noarch/beautifulsoup4-4.11.1-pyha770c72_0.tar.bz2#eeec8814bd97b2681f708bb127478d7d
-https://conda.anaconda.org/conda-forge/osx-64/black-22.10.0-py311h6eed73b_2.tar.bz2#ba682d521bf66779ec72ce63d3636197
 https://conda.anaconda.org/conda-forge/noarch/bleach-5.0.1-pyhd8ed1ab_0.tar.bz2#1f5151d37e4a2b1137f81c89a3a769f2
 https://conda.anaconda.org/conda-forge/noarch/cattrs-22.2.0-pyhd8ed1ab_0.tar.bz2#5dacf4d924ae284579288e378b1f5943
 https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_3.conda#5967be4da33261eada7cc79593f71088
 https://conda.anaconda.org/conda-forge/noarch/comm-0.1.2-pyhd8ed1ab_0.conda#3c78af4752bb1600ebe5e83ef4588eaa
 https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2#6aa0173c14befcd577ded130cf6f22f5
-https://conda.anaconda.org/conda-forge/osx-64/coverage-7.0.0-py311h5547dcb_0.conda#6acff7c4295f888de890da73101654ba
+https://conda.anaconda.org/conda-forge/osx-64/coverage-7.0.3-py311h5547dcb_0.conda#54d168637e920d2d5dc516195511f51c
 https://conda.anaconda.org/conda-forge/osx-64/curl-7.87.0-h6df9250_0.conda#af1db2937ff4a1af6440630102dd18bc
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
 https://conda.anaconda.org/conda-forge/noarch/hypothesis-6.61.0-pyha770c72_0.conda#df3897a189f054eaa666a3945fd574ab
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.2.0-pyha770c72_0.conda#2e8eec7a08bcf85547a3778225f00634
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/osx-64/jupyter_core-5.1.0-py311h6eed73b_0.conda#56d2d9edeb32553e2bf590171998dfdc
 https://conda.anaconda.org/conda-forge/osx-64/libblas-3.9.0-16_osx64_openblas.tar.bz2#644d63e9379867490b67bace400b2a0f
 https://conda.anaconda.org/conda-forge/noarch/livereload-2.6.3-pyh9f0ad1d_0.tar.bz2#b7190e3ec3eff52839434bf4698e2d62
 https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-2.1.0-pyhd8ed1ab_0.tar.bz2#d821ebc1ebe21d4cac2555278c2cd970
@@ -231,14 +231,14 @@ https://conda.anaconda.org/conda-forge/osx-64/mypy-0.991-py311h5547dcb_0.tar.bz2
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2#330448ce4403cc74990ac07c555942a1
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.0-pyhd8ed1ab_2.tar.bz2#ac82c7aebc282e6ac0450fca012ca78c
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/osx-64/python-libarchive-c-4.0-py311h6eed73b_2.tar.bz2#3f638415e24cec2635e49949205c3d1a
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
 https://conda.anaconda.org/conda-forge/noarch/robotframework-robocop-1.12.0-pyhd8ed1ab_0.tar.bz2#37e6dad59a24e6d7ff64a533c4135f57
 https://conda.anaconda.org/conda-forge/noarch/robotframework-stacktrace-0.4.1-pyhd8ed1ab_0.tar.bz2#3dc788e294fd159537c931dbb964511e
-https://conda.anaconda.org/conda-forge/osx-64/sqlalchemy-1.4.45-py311h5547dcb_0.conda#ef802be4ed86c316992dd5d2ab712bd0
+https://conda.anaconda.org/conda-forge/osx-64/sqlalchemy-1.4.46-py311h5547dcb_0.conda#032553a3ed76ef61210c7afc43f6f738
 https://conda.anaconda.org/conda-forge/noarch/terminado-0.17.1-pyhd1c38e8_0.conda#046120b71d8896cb7faef78bfdbfee1e
 https://conda.anaconda.org/conda-forge/noarch/tinycss2-1.2.1-pyhd8ed1ab_0.tar.bz2#7234c9eefff659501cd2fe0d2ede4d48
 https://conda.anaconda.org/conda-forge/noarch/traittypes-0.2.1-pyh9f0ad1d_2.tar.bz2#7d32ccb5334a6822c28af3e864550618
@@ -247,70 +247,73 @@ https://conda.anaconda.org/conda-forge/noarch/url-normalize-1.4.3-pyhd8ed1ab_0.t
 https://conda.anaconda.org/conda-forge/osx-64/argon2-cffi-bindings-21.2.0-py311h5547dcb_3.tar.bz2#c09459e349fa61afc352f473766de109
 https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py311h5547dcb_1005.tar.bz2#5f97ac938a90d06eebea42c321abe0d7
 https://conda.anaconda.org/conda-forge/osx-64/cmarkgfm-0.8.0-py311h5547dcb_2.tar.bz2#69cd422f24f98fb4f8a9a896798bff06
-https://conda.anaconda.org/conda-forge/osx-64/cryptography-38.0.4-py311h61927ef_0.conda#d7415ad7ae6c27050886ab2b583f09ca
+https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.0-py311h61927ef_0.conda#b2893b3bd6cb56dbac5278a976fc0502
 https://conda.anaconda.org/conda-forge/noarch/doit-0.36.0-pyhd8ed1ab_0.tar.bz2#fc5e53d070f1ee7bb38c2ece282dcb82
 https://conda.anaconda.org/conda-forge/osx-64/git-2.39.0-pl5321h0195497_0.conda#29c45dfbe0ba95305ac12ad7d74a715d
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.2.0-hd8ed1ab_0.conda#fe869d480dad3299a8ac60f31fb10bbd
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
-https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1ab_0.tar.bz2#243f63592c8e449f40cd42eb5cf32f40
 https://conda.anaconda.org/conda-forge/osx-64/libcblas-3.9.0-16_osx64_openblas.tar.bz2#28592eab0f05bcf9969789e87f754e11
 https://conda.anaconda.org/conda-forge/osx-64/liblapack-3.9.0-16_osx64_openblas.tar.bz2#406ad426aade5578b90544cc2ed4a79b
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytest-asyncio-0.20.3-pyhd8ed1ab_0.conda#aa462bf71d7b327dcc00ae523f8923ef
 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7
 https://conda.anaconda.org/conda-forge/noarch/pytest-metadata-2.0.4-pyhd8ed1ab_0.tar.bz2#7ac02a65917993d38ca1bfd7b87208e4
 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.1.0-pyhd8ed1ab_0.conda#e82f8fb903d7c4a59c77954759c341f9
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.2-pyhd8ed1ab_0.conda#e7df0fdd404616638df5ece6e69ba7af
 https://conda.anaconda.org/conda-forge/osx-64/trio-0.22.0-py311h6eed73b_1.tar.bz2#71a739c4b0b1e17cfd27cfdf828d52a8
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
 https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2#00ba804b54f451d102f6a7615f08470d
 https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-21.3.0-pyhd8ed1ab_0.tar.bz2#a0b402db58f73aaab8ee0ca1025a362e
+https://conda.anaconda.org/conda-forge/osx-64/black-22.10.0-py311h6eed73b_2.tar.bz2#ba682d521bf66779ec72ce63d3636197
+https://conda.anaconda.org/conda-forge/osx-64/jupyter_core-5.1.2-py311h6eed73b_0.conda#0088568cfcd700c99e50cd18c343d92b
 https://conda.anaconda.org/conda-forge/osx-64/keyring-23.13.1-py311h6eed73b_0.conda#ae2618c59c8f3481aa7014de862c6d57
-https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
-https://conda.anaconda.org/conda-forge/osx-64/numpy-1.24.0-py311h62c7003_0.conda#493ac201529820988e0b889ab0bd1d42
+https://conda.anaconda.org/conda-forge/osx-64/numpy-1.24.1-py311h62c7003_0.conda#b1994c9a248f5a0b45b641f185dbaede
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
 https://conda.anaconda.org/conda-forge/noarch/trio-websocket-0.9.2-pyhd8ed1ab_0.tar.bz2#7acf3fc982eef23b24aed10e80d5dc99
-https://conda.anaconda.org/conda-forge/noarch/ipython-8.7.0-pyhd1c38e8_0.conda#54d2e0754d7ecb42cd6a6d1795241a16
-https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
+https://conda.anaconda.org/conda-forge/noarch/ipython-8.8.0-pyhd1c38e8_0.conda#92012d3aee304230e25f564e7746e8dd
+https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
+https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
+https://conda.anaconda.org/conda-forge/osx-64/numcodecs-0.11.0-py311h814d153_1.conda#21f2ae35161c19b8c4ad0791d12ef2a3
 https://conda.anaconda.org/conda-forge/osx-64/pandas-1.5.2-py311hd84f3f5_0.conda#c061bfc7a65e7b7a1757d2476056acc3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-tidy-3.3.2-pyhd8ed1ab_0.tar.bz2#354a5c374999c2688332c073e2450951
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-22.10.0-hd8ed1ab_2.tar.bz2#80112c21a14035fe1d786f082ce27978
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.19.4-pyh736e0ef_0.conda#dbd888b31f82ca9b335ec30d26811d5e
-https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
+https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
 https://conda.anaconda.org/conda-forge/noarch/selenium-4.7.2-pyhd8ed1ab_0.conda#4f6238a5e80996ee0bbee28b487aada5
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
-https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
+https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-0.9.7-pyhd8ed1ab_0.conda#399c98b39eb6bdc4b1d40b7611a6d384
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1ab_0.tar.bz2#a4cd20af9711434f89d1ec0d2b3ae6ba
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
-https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.12.0-pyhd8ed1ab_0.tar.bz2#fe4a16a5ffc6ff74d4a479a44f6bf6a2
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-pyhd8ed1ab_0.tar.bz2#9204ee150d1e42f4c995376a8adff03c
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
+https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/osx-64_3.7_environment.conda.lock b/.github/locks/osx-64_3.7_environment.conda.lock
index 340bd854..f9a728f2 100644
--- a/.github/locks/osx-64_3.7_environment.conda.lock
+++ b/.github/locks/osx-64_3.7_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.7,<3.8
 # dependencies: []
@@ -111,7 +113,7 @@ https://conda.anaconda.org/conda-forge/osx-64/brotli-bin-1.0.9-hb7f2c08_8.tar.bz
 https://conda.anaconda.org/conda-forge/osx-64/freetype-2.12.1-h3f81eb7_1.conda#852224ea3e8991a8342228eab274840e
 https://conda.anaconda.org/conda-forge/osx-64/krb5-1.20.1-h049b76e_0.conda#db11fa2968ef0837288fe2d7f5b77a50
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran-5.0.0-11_3_0_h97931a8_27.conda#7d25335e67256924aa04de681e68e807
-https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.47.0-h5aae05b_1.tar.bz2#19d5ae4be3e4b3cfa5696f3667e8c631
+https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.51.0-he2ab024_0.conda#910e7f012beecf5d845a993feb9259a9
 https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.10.0-h47af595_3.tar.bz2#5a28624eeb7812b585b9e2d75f846ba2
 https://conda.anaconda.org/conda-forge/osx-64/libtiff-4.4.0-h6268bbc_5.conda#551fc78ba147767ea5905d0746e2fbb5
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.3-hb9e07b5_0.tar.bz2#13ba8bf8f44cdac2e5401dac20a36040
@@ -163,19 +165,20 @@ https://conda.anaconda.org/conda-forge/osx-64/markupsafe-2.1.1-py37h69ee0a8_1.ta
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.0.4-py37h229a17a_0.tar.bz2#55193f0d7a4199ac25a50be0b98caa8d
 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19
 https://conda.anaconda.org/conda-forge/osx-64/mypy_extensions-0.4.3-py37hf985489_5.tar.bz2#80b8a92e44bf314fe5b92fbe0b3186c2
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
+https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.1-py37h8052db5_0.tar.bz2#e6ac5703d3e21e9ab11df6c2ef182762
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
 https://conda.anaconda.org/conda-forge/osx-64/pillow-9.2.0-py37ha6ba2b9_2.tar.bz2#4be8072ef4253ba54dc03fd4489b0062
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/osx-64/psutil-5.9.3-py37h8052db5_0.tar.bz2#cb0d26bbefde4a82fc4834ec3b088589
 https://conda.anaconda.org/conda-forge/noarch/ptyprocess-0.7.0-pyhd3deb0d_0.tar.bz2#359eeb6536da0e687af562ed265ec263
@@ -219,7 +222,7 @@ https://conda.anaconda.org/conda-forge/osx-64/unicodedata2-14.0.0-py37h69ee0a8_1
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/noarch/anyio-3.6.2-pyhd8ed1ab_0.tar.bz2#8ada050fa88f26916fc1e76e368a49fd
 https://conda.anaconda.org/conda-forge/noarch/babel-2.11.0-pyhd8ed1ab_0.tar.bz2#2ea70fde8d581ba9425a761609eed6ba
@@ -237,7 +240,7 @@ https://conda.anaconda.org/conda-forge/osx-64/git-2.39.0-pl5321h0195497_0.conda#
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
 https://conda.anaconda.org/conda-forge/osx-64/importlib-metadata-4.11.4-py37hf985489_0.tar.bz2#5433686b318d1725f4783d0c08523566
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
@@ -252,7 +255,7 @@ https://conda.anaconda.org/conda-forge/osx-64/mypy-0.982-py37h8052db5_0.tar.bz2#
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2#330448ce4403cc74990ac07c555942a1
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
 https://conda.anaconda.org/conda-forge/noarch/robotframework-robocop-1.12.0-pyhd8ed1ab_0.tar.bz2#37e6dad59a24e6d7ff64a533c4135f57
@@ -275,9 +278,10 @@ https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1
 https://conda.anaconda.org/conda-forge/osx-64/kiwisolver-1.4.4-py37h229a17a_0.tar.bz2#542ec4f3e23b103f9fcafb9ab26e859c
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
 https://conda.anaconda.org/conda-forge/osx-64/numpy-1.21.6-py37h345d48f_0.tar.bz2#2aaa4d38d44a9a69f64bf757a5531165
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/osx-64/sqlalchemy-1.4.42-py37h8052db5_0.tar.bz2#46b721181843590249cbf47e587dfebe
 https://conda.anaconda.org/conda-forge/osx-64/trio-0.21.0-py37hf985489_0.tar.bz2#5c48a7515890f04d45a83015096f5200
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
@@ -288,10 +292,11 @@ https://conda.anaconda.org/conda-forge/osx-64/hypothesis-6.56.3-py37hf985489_1.t
 https://conda.anaconda.org/conda-forge/osx-64/keyring-23.9.3-py37hf985489_0.tar.bz2#adf5d27db8dbbde19e274de351295805
 https://conda.anaconda.org/conda-forge/osx-64/matplotlib-base-3.5.3-py37h3748cd6_2.tar.bz2#ad309097b34ab82b42bc8eac0668d226
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
+https://conda.anaconda.org/conda-forge/osx-64/numcodecs-0.10.2-py37hf6dfe07_0.tar.bz2#f836a75499b39404051c1c0efbfb5141
 https://conda.anaconda.org/conda-forge/osx-64/pandas-1.3.5-py37h5b83a90_0.tar.bz2#f5b03c55f0d4bd06495b726ed574412c
 https://conda.anaconda.org/conda-forge/osx-64/pluggy-1.0.0-py37hf985489_3.tar.bz2#c01a618055fe641f37b92e55b9104674
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
@@ -323,8 +328,7 @@ https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1a
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
 https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
@@ -334,7 +338,7 @@ https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-py
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/osx-64_lock-environment.conda.lock b/.github/locks/osx-64_lock-environment.conda.lock
index 5e6af047..a43d16e1 100644
--- a/.github/locks/osx-64_lock-environment.conda.lock
+++ b/.github/locks/osx-64_lock-environment.conda.lock
@@ -3,15 +3,16 @@
 #   - nodefaults
 
 # dependencies:
-#   - conda-lock >=1.2,<1.3
+#   - conda-lock >=1.3,<1.4
 #   - mamba >=1.1.0,<1.2
 #   - python >=3.11,<3.12
+#   - conda !=22.11.1
 # dependencies: []
 
 @EXPLICIT
 https://conda.anaconda.org/conda-forge/osx-64/bzip2-1.0.8-h0d85af4_4.tar.bz2#37edc4e6304ca87316e160f5ca0bd1b5
 https://conda.anaconda.org/conda-forge/osx-64/c-ares-1.18.1-h0d85af4_0.tar.bz2#00b3e98a61e6430808fe7a2534681f28
-https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2022.9.24-h033912b_0.tar.bz2#67b268c32433047914482def1ce215c2
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
 https://conda.anaconda.org/conda-forge/osx-64/libcxx-14.0.6-hccf4f1f_0.tar.bz2#208a6a874b073277374de48a782f6b10
 https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-haf1e3a3_1.tar.bz2#79dc2be110b2a3d1e97ec21f691c50ad
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
@@ -21,87 +22,89 @@ https://conda.anaconda.org/conda-forge/osx-64/lzo-2.10-haf1e3a3_1000.tar.bz2#0b6
 https://conda.anaconda.org/conda-forge/osx-64/ncurses-6.3-h96cf925_1.tar.bz2#76217ebfbb163ff2770a261f955a5861
 https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-4-hd8ed1ab_3.tar.bz2#878f923dd6acc8aeb47a75da6c4098be
 https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.11-3_cp311.conda#5e0a069a585445333868d2c6651c3b3f
-https://conda.anaconda.org/conda-forge/osx-64/reproc-14.2.3-h0d85af4_0.tar.bz2#6f87f4707e4daf5823ce56dce5d9fbea
+https://conda.anaconda.org/conda-forge/osx-64/reproc-14.2.4-hb7f2c08_0.conda#02b5e8cb2a08ac9c816a91b49070b8e2
 https://conda.anaconda.org/conda-forge/noarch/tzdata-2022g-h191b570_0.conda#51fc4fcfb19f5d95ffc8c339db5068e8
 https://conda.anaconda.org/conda-forge/osx-64/xz-5.2.6-h775f41a_0.tar.bz2#a72f9d4ea13d55d745ff1ed594747f10
 https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2#d7e08fcf8259d742156188e8762b4d20
 https://conda.anaconda.org/conda-forge/osx-64/fmt-9.1.0-hb8565cd_0.tar.bz2#310d897883dbdd88555d6321a4c2e6e8
 https://conda.anaconda.org/conda-forge/osx-64/icu-70.1-h96cf925_0.tar.bz2#376635049e9b9b0bb875efd39dcd7b3b
 https://conda.anaconda.org/conda-forge/osx-64/libedit-3.1.20191231-h0678c8f_2.tar.bz2#6016a8a1d0e63cac3de2c352cd40208b
-https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.22-hd9580d2_0.tar.bz2#068ed0617893ecbccbf65a32ea1e8056
+https://conda.anaconda.org/conda-forge/osx-64/libsolv-0.7.23-hbc0c0cd_0.conda#f032439375fa26ce944d8a70f81682a4
 https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_0.tar.bz2#ceb13b6726534b96e3b4e3dda91e9050
 https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.3-he49afe7_1.tar.bz2#05c08241b66631c00ca4f9e0b75320bc
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.0.7-hfd90126_1.conda#7a3fb6d40e0aa5dbb5b4ef54462f00a8
 https://conda.anaconda.org/conda-forge/osx-64/readline-8.1.2-h3899abd_0.tar.bz2#89fa404901fa8fb7d4f4e07083b8d635
-https://conda.anaconda.org/conda-forge/osx-64/reproc-cpp-14.2.3-he49afe7_0.tar.bz2#7dafcfaa471cd16cbd73832cefc39770
+https://conda.anaconda.org/conda-forge/osx-64/reproc-cpp-14.2.4-hf0c8a7f_0.conda#aef754e1111b466a15227427f65a1733
 https://conda.anaconda.org/conda-forge/osx-64/tk-8.6.12-h5dbffcc_0.tar.bz2#8e9480d9c47061db2ed1b4ecce519a7f
 https://conda.anaconda.org/conda-forge/osx-64/yaml-cpp-0.7.0-hf0c8a7f_2.tar.bz2#06c92b93b45ed2c842eb0893c5d2552a
 https://conda.anaconda.org/conda-forge/osx-64/zstd-1.5.2-hfa58983_4.tar.bz2#0b446e84f3ccf085e590dc1f73eebe3f
-https://conda.anaconda.org/conda-forge/osx-64/krb5-1.19.3-hb98e516_0.tar.bz2#8acf20165e07870bc65510a363ff45bb
-https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.47.0-h5aae05b_1.tar.bz2#19d5ae4be3e4b3cfa5696f3667e8c631
+https://conda.anaconda.org/conda-forge/osx-64/krb5-1.20.1-h049b76e_0.conda#db11fa2968ef0837288fe2d7f5b77a50
+https://conda.anaconda.org/conda-forge/osx-64/libnghttp2-1.51.0-he2ab024_0.conda#910e7f012beecf5d845a993feb9259a9
 https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.10.0-h47af595_3.tar.bz2#5a28624eeb7812b585b9e2d75f846ba2
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.3-hb9e07b5_0.tar.bz2#13ba8bf8f44cdac2e5401dac20a36040
 https://conda.anaconda.org/conda-forge/osx-64/python-3.11.0-h559f36b_0_cpython.tar.bz2#9eac7bb07be3725945c23c4ae90f9faa
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/cachy-0.3.0-pyhd8ed1ab_1.tar.bz2#5dfee17f24e2dfd18d7392b48c9351e2
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d
+https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/crashtest-0.3.1-pyhd8ed1ab_0.tar.bz2#b8477552274c1cfdb533e954c76523f1
 https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.6-pyhd8ed1ab_0.tar.bz2#b65b4d50dbd2d50fa0aeac367ec9eed7
-https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.2-pyhd8ed1ab_0.conda#0f09c2bc17ddd8732be8e5b99297c7ce
+https://conda.anaconda.org/conda-forge/noarch/filelock-3.9.0-pyhd8ed1ab_0.conda#1addc115923d646ca19ed90edc413506
 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed
-https://conda.anaconda.org/conda-forge/osx-64/libarchive-3.5.2-hbf7dfe4_3.tar.bz2#57f1c0e98ad3d4836d66d457f3690dc9
-https://conda.anaconda.org/conda-forge/osx-64/libcurl-7.86.0-h581aaea_1.tar.bz2#af83102fc53762fb78e27657b540756f
+https://conda.anaconda.org/conda-forge/osx-64/libarchive-3.6.2-h6d8d9f1_0.conda#bbd5c956d814ca90db82a759a0c58678
+https://conda.anaconda.org/conda-forge/osx-64/libcurl-7.87.0-h6df9250_0.conda#10b51d82bf33b95e0abe6a224be254c8
 https://conda.anaconda.org/conda-forge/osx-64/markupsafe-2.1.1-py311h5547dcb_2.tar.bz2#cd912231195461aa21aa4e8f1eff1276
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
 https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.0.4-py311hd2070f0_1.tar.bz2#e91973b43c03d74de80de087ff46e393
+https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pastel-0.2.1-pyhd8ed1ab_0.tar.bz2#a4eea5bff523f26442405bc5d1f52adb
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/osx-64/pycosat-0.6.4-py311h5547dcb_1.tar.bz2#229e642050372d50ebdc24e2265ce8b2
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pylev-1.4.0-pyhd8ed1ab_0.tar.bz2#edf8651c4379d9d1495ad6229622d150
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyha2e5f31_6.tar.bz2#2a7de29fb590ca14b5243c4c812c8025
 https://conda.anaconda.org/conda-forge/osx-64/pyyaml-6.0-py311h5547dcb_5.tar.bz2#8d1e456914ce961119b07f396187a564
 https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml.clib-0.2.7-py311h5547dcb_1.conda#fdae97fc41b9e4aa53d644cca8ba6c54
 https://conda.anaconda.org/conda-forge/osx-64/ruamel_yaml-0.15.80-py311h5547dcb_1008.tar.bz2#42c63993b1aaba9dc3c69a36e368d11c
-https://conda.anaconda.org/conda-forge/noarch/setuptools-65.5.1-pyhd8ed1ab_0.tar.bz2#cfb8dc4d9d285ca5fb1177b9dd450e33
+https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
+https://conda.anaconda.org/conda-forge/noarch/smmap-3.0.5-pyh44b312d_0.tar.bz2#3a8dc70789709aa315325d5df06fb7e4
 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96
 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36
 https://conda.anaconda.org/conda-forge/noarch/typing-3.10.0.0-pyhd8ed1ab_0.tar.bz2#e6573ac68718f17b9d4f5c8eda3190f2
 https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72_0.tar.bz2#2d93b130d148d7fc77e583677792fc6a
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
-https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_2.tar.bz2#6b2c5fa2e823356561717fc8b8ce3433
+https://conda.anaconda.org/conda-forge/osx-64/cffi-1.15.1-py311ha86e640_3.conda#5967be4da33261eada7cc79593f71088
 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.2-pyhd8ed1ab_1.tar.bz2#72a46ffc25701c173932fd55cf0965d3
 https://conda.anaconda.org/conda-forge/noarch/clikit-0.6.2-pyh9f0ad1d_0.tar.bz2#159273f717a11e53b2656f8b6521a5e2
+https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.10-pyhd8ed1ab_0.conda#3706d2f3d7cb5dae600c833345a76132
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.1.0-pyha770c72_0.conda#46a62e35b9ae515cf0e49afc7fe0e7ef
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/osx-64/libmamba-1.1.0-h8b63968_2.conda#b2f3194abef248954cbd738d602fc6a5
-https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85
+https://conda.anaconda.org/conda-forge/osx-64/libmamba-1.1.0-hdec3fd3_3.conda#377e5243ee5ca3a4394264e9a3d38673
 https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.21-py311h5547dcb_2.tar.bz2#f5718d3aec1264762876c51fad9ae4bb
 https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.11.6-pyha770c72_0.tar.bz2#471bf9e605820b59988e830382b8d654
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026
-https://conda.anaconda.org/conda-forge/osx-64/virtualenv-20.17.0-py311h6eed73b_0.conda#c3b557fa52fbfd60772429875906dc26
 https://conda.anaconda.org/conda-forge/osx-64/brotlipy-0.7.0-py311h5547dcb_1005.tar.bz2#5f97ac938a90d06eebea42c321abe0d7
-https://conda.anaconda.org/conda-forge/osx-64/cryptography-38.0.4-py311h61927ef_0.conda#d7415ad7ae6c27050886ab2b583f09ca
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.1.0-hd8ed1ab_0.conda#3dc2248927de739b4d2e2da9a9972bfe
-https://conda.anaconda.org/conda-forge/osx-64/libmambapy-1.1.0-py311hcc19a12_2.conda#cc99f203f28f3a4826657de7a4bab9d7
-https://conda.anaconda.org/conda-forge/osx-64/pydantic-1.10.2-py311h5547dcb_1.tar.bz2#edb88a2277e81771adbf5f043e45e9c3
+https://conda.anaconda.org/conda-forge/osx-64/cryptography-39.0.0-py311h61927ef_0.conda#b2893b3bd6cb56dbac5278a976fc0502
+https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.30-pyhd8ed1ab_0.conda#0c217ab2f5ef6925e4e52c70b57cfc4a
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
+https://conda.anaconda.org/conda-forge/osx-64/libmambapy-1.1.0-py311hcc19a12_3.conda#fc1b3c8a2451ea2c679e6332bfd5b52e
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
+https://conda.anaconda.org/conda-forge/osx-64/pydantic-1.10.4-py311h5547dcb_0.conda#0601ab2dab4e5c0542bbdc8d1cbb7b62
 https://conda.anaconda.org/conda-forge/osx-64/zstandard-0.19.0-py311hebd4beb_1.conda#b0d4f55c803038fd429494acf684e6ef
 https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.7.0-pyhd8ed1ab_1.conda#1a2fa9e53cfbc2e4d9ab21990805a436
-https://conda.anaconda.org/conda-forge/osx-64/keyring-23.11.0-py311h6eed73b_0.tar.bz2#d2cad432958c07e3b3999a9a92d7f5e9
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/osx-64/keyring-23.13.1-py311h6eed73b_0.conda#ae2618c59c8f3481aa7014de862c6d57
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
+https://conda.anaconda.org/conda-forge/osx-64/virtualenv-20.17.1-py311h6eed73b_0.conda#e1d0ae9173b110079196d1ddbe2d3b24
 https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.0.2-pyh38be061_0.conda#44800e9bd13143292097c65e57323038
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
-https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.12-pyhd8ed1ab_1.tar.bz2#e4b40ac0d53e81ebf8892e3b3ca9c1cf
+https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.11-pyhd8ed1ab_0.tar.bz2#6eefee9888f33f150b5d44d616b1a613
 https://conda.anaconda.org/conda-forge/osx-64/conda-22.9.0-py311h6eed73b_2.tar.bz2#d18ef2c39925384887a22371e00b1160
 https://conda.anaconda.org/conda-forge/noarch/ensureconda-1.4.3-pyhd8ed1ab_0.tar.bz2#c99ae3abf501990769047b4b40a98f17
-https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.2.1-pyhd8ed1ab_1.tar.bz2#7b1dde4760c5c554523fead6c2771af2
-https://conda.anaconda.org/conda-forge/osx-64/mamba-1.1.0-py311h8082e30_2.conda#dfe1436cbf1bd76d461020d3c48659e0
+https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.3.0-pyhd8ed1ab_0.conda#1165b4b0171fad7555822fe3a85365ed
+https://conda.anaconda.org/conda-forge/osx-64/mamba-1.1.0-py311h8082e30_3.conda#60fad1b77b7e67c23e05afd451000475
diff --git a/.github/locks/win-64_3.11_environment.conda.lock b/.github/locks/win-64_3.11_environment.conda.lock
index 49e479e7..5de0c768 100644
--- a/.github/locks/win-64_3.11_environment.conda.lock
+++ b/.github/locks/win-64_3.11_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.11,<3.12
 # dependencies: []
@@ -90,7 +92,6 @@ https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_0.tar.bz2#
 https://conda.anaconda.org/conda-forge/win-64/python-3.11.0-hcf16a7b_0_cpython.tar.bz2#13ee3577afc291dabd2d9edc59736688
 https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.4-h0e60522_1.tar.bz2#e1aff0583dda5fb917eb3d2c1025aa80
 https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h7755175_4.tar.bz2#13acb3626fcc8c0577249f3a7b6129f4
-https://conda.anaconda.org/conda-forge/noarch/_ipython_minor_entry_point-8.7.0-h0c17e10_0.conda#8a63fb4d63db7b245ecf3c6f907935ff
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.12-py_0.tar.bz2#2489a97287f90176ecdc3ca982b4b0a0
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
@@ -129,18 +130,19 @@ https://conda.anaconda.org/conda-forge/win-64/markupsafe-2.1.1-py311ha68e1ae_2.t
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.0.4-py311h005e61a_1.tar.bz2#ef561ef7fcf37af359d9cb424a6346c1
 https://conda.anaconda.org/conda-forge/win-64/mypy_extensions-0.4.3-py311h1ea47a8_6.tar.bz2#0fbb8ea0a811a9287a6f092165d0af42
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
 https://conda.anaconda.org/conda-forge/noarch/networkx-2.8.8-pyhd8ed1ab_0.tar.bz2#bb45ff9deddb045331fd039949f39650
+https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.3-py311h5443569_0.conda#6efb021a81cc38a38d8ae366139304a6
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/pluggy-1.0.0-pyhd8ed1ab_5.tar.bz2#7d301a0d25f424d96175f810935f0da9
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/win-64/psutil-5.9.4-py311ha68e1ae_0.tar.bz2#2484db2971c44ba7fc486a7cf2a456bf
@@ -148,12 +150,12 @@ https://conda.anaconda.org/conda-forge/noarch/pure_eval-0.2.2-pyhd8ed1ab_0.tar.b
 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pyflakes-3.0.1-pyhd8ed1ab_0.conda#44b7d77d96560c93e0e11437a3c35254
-https://conda.anaconda.org/conda-forge/win-64/pyrsistent-0.19.2-py311ha68e1ae_0.tar.bz2#8769b760c7baaab19ec7dbf770ef7cb5
+https://conda.anaconda.org/conda-forge/win-64/pyrsistent-0.19.3-py311ha68e1ae_0.conda#3f2780a49f0b4bb2c622f7cf098e3d06
 https://conda.anaconda.org/conda-forge/noarch/python-fastjsonschema-2.16.2-pyhd8ed1ab_0.tar.bz2#5fe4b6002f505336734ce92961b3e6a0
 https://conda.anaconda.org/conda-forge/noarch/pytz-2022.7-pyhd8ed1ab_0.conda#c8d7e34ca76d6ecc03b84bedfd99d689
 https://conda.anaconda.org/conda-forge/win-64/pywin32-304-py311h12c1d0e_2.tar.bz2#20a2d8e73b0be8e27ca4096d4f3a7053
 https://conda.anaconda.org/conda-forge/win-64/pywin32-ctypes-0.2.0-py311h1ea47a8_1006.tar.bz2#86ee973a16f5449d9ded34b512331dce
-https://conda.anaconda.org/conda-forge/win-64/pywinpty-2.0.9-py311h12c1d0e_0.tar.bz2#19350a88f0f1966b22bceac89c51dbff
+https://conda.anaconda.org/conda-forge/win-64/pywinpty-2.0.10-py311h12c1d0e_0.conda#4d7e034dc93f50757cf039a2e3183343
 https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0-py311ha68e1ae_5.tar.bz2#0c97d59d54eb52e170224b3de6ade906
 https://conda.anaconda.org/conda-forge/win-64/pyzmq-24.0.1-py311h7b3f143_1.tar.bz2#f19e3e02d0209ed21fb69a021296734b
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2#d337886e38f965bf97aaec382ff6db00
@@ -183,7 +185,7 @@ https://conda.anaconda.org/conda-forge/win-64/ujson-5.5.0-py311h12c1d0e_1.tar.bz
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyhd8ed1ab_6.tar.bz2#30878ecc4bd36e8deeea1e3c151b2e0b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/win-64/ansi2html-1.8.0-py311h1ea47a8_1.tar.bz2#37eaf0b4baf7aa03a7d38339c31db411
@@ -198,23 +200,22 @@ https://conda.anaconda.org/conda-forge/win-64/cffi-1.15.1-py311h7d9ee11_3.conda#
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-win_pyhd8ed1ab_2.tar.bz2#6b58680207b526c42dcff68b543803dd
 https://conda.anaconda.org/conda-forge/noarch/comm-0.1.2-pyhd8ed1ab_0.conda#3c78af4752bb1600ebe5e83ef4588eaa
 https://conda.anaconda.org/conda-forge/noarch/commonmark-0.9.1-py_0.tar.bz2#6aa0173c14befcd577ded130cf6f22f5
-https://conda.anaconda.org/conda-forge/win-64/coverage-7.0.0-py311ha68e1ae_0.conda#1ea257b5a9af24c5521b1df01954f878
+https://conda.anaconda.org/conda-forge/win-64/coverage-7.0.3-py311ha68e1ae_0.conda#a273a17a762e170a7467f6614bfcf830
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.2.0-pyha770c72_0.conda#2e8eec7a08bcf85547a3778225f00634
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/win-64/jupyter_core-5.1.0-py311h1ea47a8_0.conda#c8a3dc6bd2ff9201d74e557e57e26c6d
 https://conda.anaconda.org/conda-forge/noarch/livereload-2.6.3-pyh9f0ad1d_0.tar.bz2#b7190e3ec3eff52839434bf4698e2d62
 https://conda.anaconda.org/conda-forge/noarch/markdown-it-py-2.1.0-pyhd8ed1ab_0.tar.bz2#d821ebc1ebe21d4cac2555278c2cd970
 https://conda.anaconda.org/conda-forge/noarch/matplotlib-inline-0.1.6-pyhd8ed1ab_0.tar.bz2#b21613793fcc81d944c76c9f2864a7de
 https://conda.anaconda.org/conda-forge/win-64/mypy-0.991-py311ha68e1ae_0.tar.bz2#1b57f2dd3853810614561d90c7aafec3
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2#56cd9fe388baac0e90c7149cfac95b60
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.2.0-pyhd8ed1ab_2.tar.bz2#ac82c7aebc282e6ac0450fca012ca78c
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
@@ -222,7 +223,7 @@ https://conda.anaconda.org/conda-forge/win-64/python-libarchive-c-4.0-py311h1ea4
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
 https://conda.anaconda.org/conda-forge/noarch/robotframework-robocop-1.12.0-pyhd8ed1ab_0.tar.bz2#37e6dad59a24e6d7ff64a533c4135f57
 https://conda.anaconda.org/conda-forge/noarch/robotframework-stacktrace-0.4.1-pyhd8ed1ab_0.tar.bz2#3dc788e294fd159537c931dbb964511e
-https://conda.anaconda.org/conda-forge/win-64/sqlalchemy-1.4.45-py311ha68e1ae_0.conda#852a046dc142eb4bde35ea63725377e3
+https://conda.anaconda.org/conda-forge/win-64/sqlalchemy-1.4.46-py311ha68e1ae_0.conda#f0c5f7f520e0a1e619b7501450a0fef7
 https://conda.anaconda.org/conda-forge/win-64/tbb-2021.7.0-h91493d7_1.conda#39365b918d4f04909485f3055b131c86
 https://conda.anaconda.org/conda-forge/noarch/terminado-0.17.0-pyh08f2357_0.tar.bz2#0152a609d5748ed9887d195b1e61a6c9
 https://conda.anaconda.org/conda-forge/noarch/tinycss2-1.2.1-pyhd8ed1ab_0.tar.bz2#7234c9eefff659501cd2fe0d2ede4d48
@@ -230,75 +231,77 @@ https://conda.anaconda.org/conda-forge/noarch/traittypes-0.2.1-pyh9f0ad1d_2.tar.
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026
 https://conda.anaconda.org/conda-forge/noarch/url-normalize-1.4.3-pyhd8ed1ab_0.tar.bz2#7c4076e494f0efe76705154ac9302ba6
 https://conda.anaconda.org/conda-forge/win-64/argon2-cffi-bindings-21.2.0-py311ha68e1ae_3.tar.bz2#c321cd825b72a2073dfb3f92ce1507fb
-https://conda.anaconda.org/conda-forge/win-64/black-22.10.0-py311h1ea47a8_2.tar.bz2#6c56efbb3ceb005c744f3c3bd13d88d2
 https://conda.anaconda.org/conda-forge/win-64/brotlipy-0.7.0-py311ha68e1ae_1005.tar.bz2#dd9604ece454103e7210110c6d343e37
 https://conda.anaconda.org/conda-forge/win-64/cmarkgfm-0.8.0-py311ha68e1ae_2.tar.bz2#206cb594ef199270b7e0d3d17aa87cbe
-https://conda.anaconda.org/conda-forge/win-64/cryptography-38.0.4-py311h28e9c30_0.conda#369bad555cfdd4094409411ac563de32
+https://conda.anaconda.org/conda-forge/win-64/cryptography-39.0.0-py311h28e9c30_0.conda#9e2a95fcaa6333eac22a51f2beb913ee
 https://conda.anaconda.org/conda-forge/noarch/doit-0.36.0-pyhd8ed1ab_0.tar.bz2#fc5e53d070f1ee7bb38c2ece282dcb82
 https://conda.anaconda.org/conda-forge/noarch/hypothesis-6.61.0-pyha770c72_0.conda#df3897a189f054eaa666a3945fd574ab
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.2.0-hd8ed1ab_0.conda#fe869d480dad3299a8ac60f31fb10bbd
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
-https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1ab_0.tar.bz2#243f63592c8e449f40cd42eb5cf32f40
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
 https://conda.anaconda.org/conda-forge/win-64/mkl-2022.1.0-h6a75c08_874.tar.bz2#2ff89a7337a9636029b4db9466e9f8e3
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytest-asyncio-0.20.3-pyhd8ed1ab_0.conda#aa462bf71d7b327dcc00ae523f8923ef
 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7
 https://conda.anaconda.org/conda-forge/noarch/pytest-metadata-2.0.4-pyhd8ed1ab_0.tar.bz2#7ac02a65917993d38ca1bfd7b87208e4
 https://conda.anaconda.org/conda-forge/noarch/pytest-xdist-3.1.0-pyhd8ed1ab_0.conda#e82f8fb903d7c4a59c77954759c341f9
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/noarch/stack_data-0.6.2-pyhd8ed1ab_0.conda#e7df0fdd404616638df5ece6e69ba7af
 https://conda.anaconda.org/conda-forge/win-64/trio-0.22.0-py311h1ea47a8_1.tar.bz2#1475d3775d4e2cc09c366720de842992
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
 https://conda.anaconda.org/conda-forge/noarch/wsproto-1.2.0-pyhd8ed1ab_0.tar.bz2#00ba804b54f451d102f6a7615f08470d
 https://conda.anaconda.org/conda-forge/noarch/argon2-cffi-21.3.0-pyhd8ed1ab_0.tar.bz2#a0b402db58f73aaab8ee0ca1025a362e
+https://conda.anaconda.org/conda-forge/win-64/black-22.10.0-py311h1ea47a8_2.tar.bz2#6c56efbb3ceb005c744f3c3bd13d88d2
+https://conda.anaconda.org/conda-forge/win-64/jupyter_core-5.1.2-py311h1ea47a8_0.conda#7ef4e87f4c7565bf36a1345bf2e91dfc
 https://conda.anaconda.org/conda-forge/win-64/keyring-23.13.1-py311h1ea47a8_0.conda#ff14a49b769ea59ee6709a890e17f317
 https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-16_win64_mkl.tar.bz2#d2e6f4e86cee2b4e8c27ff6884ccdc61
-https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
 https://conda.anaconda.org/conda-forge/noarch/trio-websocket-0.9.2-pyhd8ed1ab_0.tar.bz2#7acf3fc982eef23b24aed10e80d5dc99
-https://conda.anaconda.org/conda-forge/noarch/ipython-8.7.0-pyh08f2357_0.conda#d848fc38b9f250d8f6db50ac2b415539
+https://conda.anaconda.org/conda-forge/noarch/ipython-8.8.0-pyh08f2357_0.conda#00944c2f3ff64758ec2cb62fef1e0021
+https://conda.anaconda.org/conda-forge/noarch/jupyter_client-7.4.8-pyhd8ed1ab_0.conda#bd4951aa5fbf3336a249e25c90f50333
 https://conda.anaconda.org/conda-forge/win-64/libcblas-3.9.0-16_win64_mkl.tar.bz2#14c2fb03b2bb14dfa3806186ca91d557
 https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-16_win64_mkl.tar.bz2#be2f9d5712a5bb05cd900005ee752a05
-https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
+https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
 https://conda.anaconda.org/conda-forge/noarch/robotframework-tidy-3.3.2-pyhd8ed1ab_0.tar.bz2#354a5c374999c2688332c073e2450951
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-22.10.0-hd8ed1ab_2.tar.bz2#80112c21a14035fe1d786f082ce27978
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.19.4-pyh025b116_0.conda#92eef8a79941c12cc4cc5971a2f0b517
-https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
-https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.0-py311h95d790f_0.conda#c38d79b716261684d3993ee7c05300a4
+https://conda.anaconda.org/conda-forge/noarch/nbclient-0.5.13-pyhd8ed1ab_0.tar.bz2#3edde88a191701cf052216c4ba353a83
+https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.1-py311h95d790f_0.conda#9f63e4be1a15a4d4823e307a8328118c
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
 https://conda.anaconda.org/conda-forge/noarch/selenium-4.7.2-pyhd8ed1ab_0.conda#4f6238a5e80996ee0bbee28b487aada5
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
-https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
+https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
+https://conda.anaconda.org/conda-forge/win-64/numcodecs-0.11.0-py311h12c1d0e_1.conda#9b66ec550742f950ba5fdc1fe650ce26
 https://conda.anaconda.org/conda-forge/win-64/pandas-1.5.2-py311hf63dbb6_0.conda#1122deeac8e1439e91f941cfcb977e3a
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-0.9.7-pyhd8ed1ab_0.conda#399c98b39eb6bdc4b1d40b7611a6d384
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1ab_0.tar.bz2#a4cd20af9711434f89d1ec0d2b3ae6ba
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyter_server-1.23.4-pyhd8ed1ab_0.conda#35b7e9267926e864cc70ce137e6588ca
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
-https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.2.7-pyhd8ed1ab_0.conda#7d48776bb3fdfa6447267c413a480ccd
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.12.0-pyhd8ed1ab_0.tar.bz2#fe4a16a5ffc6ff74d4a479a44f6bf6a2
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-pyhd8ed1ab_0.tar.bz2#9204ee150d1e42f4c995376a8adff03c
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
+https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/win-64_3.7_environment.conda.lock b/.github/locks/win-64_3.7_environment.conda.lock
index 870453f6..c34c14b4 100644
--- a/.github/locks/win-64_3.7_environment.conda.lock
+++ b/.github/locks/win-64_3.7_environment.conda.lock
@@ -13,7 +13,6 @@
 #   - git
 #   - hypothesis
 #   - importnb
-#   - ipydatawidgets
 #   - ipython >=7
 #   - ipywidgets >=8.0.4,<9
 #   - isort
@@ -26,6 +25,8 @@
 #   - myst-nb
 #   - networkx
 #   - nodejs >=18,<19
+#   - numcodecs
+#   - orjson
 #   - packaging >=22.0
 #   - pandas
 #   - pydata-sphinx-theme
@@ -46,6 +47,7 @@
 #   - sphinx-autobuild
 #   - sphinx-autodoc-typehints
 #   - tomli
+#   - traittypes
 #   - twine
 #   - wheel
 #   # lite
@@ -54,7 +56,7 @@
 #   - python >=3.8,<3.12.0a0
 #   # this is handled out-of-band
 #   # - pip:
-#   #   - jupyterlite ==0.1.0b16
+#   #   - jupyterlite ==0.1.0b17
 # dependencies:
 #   - python >=3.7,<3.8
 # dependencies: []
@@ -150,19 +152,20 @@ https://conda.anaconda.org/conda-forge/win-64/markupsafe-2.1.1-py37hcc03f2d_1.ta
 https://conda.anaconda.org/conda-forge/noarch/mdurl-0.1.0-pyhd8ed1ab_0.tar.bz2#f8dab71fdc13b1bf29a01248b156d268
 https://conda.anaconda.org/conda-forge/noarch/mistune-2.0.4-pyhd8ed1ab_0.tar.bz2#78e0a90393b79b378b8ff6d32893d58a
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
+https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.0.4-py37h8c56517_0.tar.bz2#2e9775a744e6e7af4f1635343dcf48a6
 https://conda.anaconda.org/conda-forge/noarch/munkres-1.1.4-pyh9f0ad1d_0.tar.bz2#2ba8498c1018c1e9c61eb99b973dfe19
 https://conda.anaconda.org/conda-forge/win-64/mypy_extensions-0.4.3-py37h03978a9_5.tar.bz2#582382a5a9cf08ff0e8e41d756236c94
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.2.0-pyhd8ed1ab_0.tar.bz2#a8b2456513ed910ef418021afc5150bb
 https://conda.anaconda.org/conda-forge/noarch/nest-asyncio-1.5.6-pyhd8ed1ab_0.tar.bz2#7b868f21adde0d9b8b38f9c16836589b
 https://conda.anaconda.org/conda-forge/win-64/openjpeg-2.5.0-hc9384bd_1.tar.bz2#a6834096f8d834339eca7ef4d23bcc44
+https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.1-py37h03978a9_0.tar.bz2#b7623a90ee6b7917c224377501a1d8fb
 https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pandocfilters-1.5.0-pyhd8ed1ab_0.tar.bz2#457c2c8c08e54905d6954e79cb5b5db9
 https://conda.anaconda.org/conda-forge/noarch/parso-0.8.3-pyhd8ed1ab_0.tar.bz2#17a565a0c3899244e938cdf417e7b094
 https://conda.anaconda.org/conda-forge/noarch/pathspec-0.9.0-pyhd8ed1ab_0.tar.bz2#f93dc0ccbc0a8472624165f6e256c7d1
 https://conda.anaconda.org/conda-forge/noarch/pickleshare-0.7.5-py_1003.tar.bz2#415f0ebb6198cc2801c73438a9fb5761
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/noarch/pkgutil-resolve-name-1.3.10-pyhd8ed1ab_0.tar.bz2#89e3c7cdde7d3aaa2aee933b604dd07f
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.0-pyhd8ed1ab_0.conda#b1b2ab02d1ece1719f7fa002ad4bc70d
 https://conda.anaconda.org/conda-forge/noarch/prometheus_client-0.15.0-pyhd8ed1ab_0.tar.bz2#b260ed41427dbbe70537b3030c643b2e
 https://conda.anaconda.org/conda-forge/win-64/psutil-5.9.3-py37h51bd9d9_0.tar.bz2#331350ffb47a163d7a27c3503688eb2c
 https://conda.anaconda.org/conda-forge/noarch/py-1.11.0-pyh6c4a22f_0.tar.bz2#b4613d7e7a493916d867842a6a148054
@@ -208,7 +211,7 @@ https://conda.anaconda.org/conda-forge/win-64/unicodedata2-14.0.0-py37hcc03f2d_1
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/websocket-client-1.4.2-pyhd8ed1ab_0.tar.bz2#5309fca1777cfdd2d7ab582edb8cc41a
 https://conda.anaconda.org/conda-forge/noarch/wheel-0.38.4-pyhd8ed1ab_0.tar.bz2#c829cfb8cb826acb9de0ac1a2df0a940
-https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.4-pyhd8ed1ab_0.conda#ade1f7a86048f34e70281c8389b70d38
+https://conda.anaconda.org/conda-forge/noarch/widgetsnbextension-4.0.5-pyhd8ed1ab_0.conda#2af53b3894fb9bdbb3679c0d31028b1b
 https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyhd8ed1ab_6.tar.bz2#30878ecc4bd36e8deeea1e3c151b2e0b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
 https://conda.anaconda.org/conda-forge/noarch/anyio-3.6.2-pyhd8ed1ab_0.tar.bz2#8ada050fa88f26916fc1e76e368a49fd
@@ -226,7 +229,7 @@ https://conda.anaconda.org/conda-forge/win-64/fonttools-4.38.0-py37h51bd9d9_0.ta
 https://conda.anaconda.org/conda-forge/noarch/h11-0.14.0-pyhd8ed1ab_0.tar.bz2#b21ed0883505ba1910994f1df031a428
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
 https://conda.anaconda.org/conda-forge/win-64/importlib-metadata-4.11.4-py37h03978a9_0.tar.bz2#d18db310efd87f4f943d547ab0f9943e
-https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.1-pyhd8ed1ab_1.conda#5b48ca365913b08b819884bc21d4fb56
+https://conda.anaconda.org/conda-forge/noarch/importlib_resources-5.10.2-pyhd8ed1ab_0.conda#de76905f801c22fc43e624058574eab3
 https://conda.anaconda.org/conda-forge/noarch/isort-5.11.4-pyhd8ed1ab_0.conda#cc1909c46e375f8d4e3eb9902b21fa6a
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jedi-0.18.2-pyhd8ed1ab_0.conda#b5e695ef9c3f0d27d6cd96bf5adc9e07
@@ -240,7 +243,7 @@ https://conda.anaconda.org/conda-forge/win-64/mypy-0.982-py37h51bd9d9_0.tar.bz2#
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/win-64/pillow-9.2.0-py37h42a8222_2.tar.bz2#54c21e9ce00a14dfb528b3499eabc1c0
 https://conda.anaconda.org/conda-forge/noarch/pip-22.3.1-pyhd8ed1ab_0.tar.bz2#da66f2851b9836d3a7c5190082a45f7d
-https://conda.anaconda.org/conda-forge/noarch/pygments-2.13.0-pyhd8ed1ab_0.tar.bz2#9f478e8eedd301008b5f395bad0caaed
+https://conda.anaconda.org/conda-forge/noarch/pygments-2.14.0-pyhd8ed1ab_0.conda#c78cd16b11cd6a295484bd6c8f24bea1
 https://conda.anaconda.org/conda-forge/win-64/pysocks-1.7.1-py37h03978a9_5.tar.bz2#36f5cb952ac637d76b80e8cf66171d2d
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.0.0-pyhd8ed1ab_0.tar.bz2#e3dd7ba929a82a21c6e568c00d5b538c
@@ -264,9 +267,10 @@ https://conda.anaconda.org/conda-forge/noarch/jupyterlab_pygments-0.2.2-pyhd8ed1
 https://conda.anaconda.org/conda-forge/win-64/kiwisolver-1.4.4-py37h8c56517_0.tar.bz2#554b3933bdd6402d36fa88af21f5f07a
 https://conda.anaconda.org/conda-forge/win-64/libblas-3.9.0-16_win64_mkl.tar.bz2#d2e6f4e86cee2b4e8c27ff6884ccdc61
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.3-pyhd8ed1ab_0.conda#7a69c057183706bc7ba6ac7c9130566a
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
 https://conda.anaconda.org/conda-forge/noarch/pytoolconfig-1.2.4-pyhd8ed1ab_1.conda#830a5eeda95b64fa74c30cf3d1b4d1ae
-https://conda.anaconda.org/conda-forge/noarch/rich-12.6.0-pyhd8ed1ab_0.tar.bz2#162ed4cc104133be23e592faa1e055e3
-https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.8.0-pyhd8ed1ab_0.tar.bz2#4209b39ac3ff6533a24ec62d196c124a
+https://conda.anaconda.org/conda-forge/noarch/rich-13.0.0-pyhd8ed1ab_0.conda#f245374921a3e908a7d33cf6f45ee936
+https://conda.anaconda.org/conda-forge/noarch/robotframework-pabot-2.10.0-pyhd8ed1ab_0.conda#9daf3df4ad0c42533dd23ab56640859d
 https://conda.anaconda.org/conda-forge/win-64/sqlalchemy-1.4.42-py37h51bd9d9_0.tar.bz2#dd6adf90a1d783711f6e398888700779
 https://conda.anaconda.org/conda-forge/win-64/trio-0.21.0-py37h03978a9_0.tar.bz2#a2fe7ed3bdd86a25a695d6677f9fa8c1
 https://conda.anaconda.org/conda-forge/noarch/wcwidth-0.2.5-pyh9f0ad1d_2.tar.bz2#5266fcd697043c59621fda522b3d78ee
@@ -280,7 +284,7 @@ https://conda.anaconda.org/conda-forge/win-64/liblapack-3.9.0-16_win64_mkl.tar.b
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.7.1-pyhd8ed1ab_0.conda#facb42913140f1a399a5ebb65b30915e
 https://conda.anaconda.org/conda-forge/win-64/pluggy-1.0.0-py37h03978a9_3.tar.bz2#989525bff76b5a98de5da909f43eeb0d
 https://conda.anaconda.org/conda-forge/noarch/prompt-toolkit-3.0.36-pyha770c72_0.conda#4d79ec192e0bfd530a254006d123b9a6
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
 https://conda.anaconda.org/conda-forge/noarch/readme_renderer-37.3-pyhd8ed1ab_0.tar.bz2#82e8ab317fe8f1d2a944688438dce868
 https://conda.anaconda.org/conda-forge/noarch/rich-click-1.4-pyhd8ed1ab_0.tar.bz2#2b8b2a9974170b437c4c3025b9a8e8d8
 https://conda.anaconda.org/conda-forge/noarch/rope-1.6.0-pyhd8ed1ab_0.conda#c10a8588df896961f69e6887727fe167
@@ -296,6 +300,7 @@ https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.16.2-pyh025b116_0.tar.
 https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.5.0-pyhd8ed1ab_0.tar.bz2#293ede7de6b604f3586efbfa615ee2e1
 https://conda.anaconda.org/conda-forge/win-64/matplotlib-base-3.5.3-py37hbaab90a_2.tar.bz2#5707cb94dec1fe26c309ea579ef9d25e
 https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.2.7-pyhd8ed1ab_0.conda#dce063b1f5d6193646fc2ac43f88b77f
+https://conda.anaconda.org/conda-forge/win-64/numcodecs-0.10.2-py37hf2a7229_0.tar.bz2#d6db5444bda5766a372378295481f953
 https://conda.anaconda.org/conda-forge/win-64/pandas-1.3.5-py37h9386db6_0.tar.bz2#9c7fb468cb205bc8ff6ef30c549198d7
 https://conda.anaconda.org/conda-forge/noarch/pytest-asyncio-0.20.3-pyhd8ed1ab_0.conda#aa462bf71d7b327dcc00ae523f8923ef
 https://conda.anaconda.org/conda-forge/noarch/pytest-cov-4.0.0-pyhd8ed1ab_0.tar.bz2#c9e3f8bfdb9bfc34aa1836a6ed4b25d7
@@ -315,8 +320,7 @@ https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-0.10.1-pyhd8ed1a
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.0.0-pyhd8ed1ab_0.tar.bz2#2acaef9c04081dc3644501ac575953bf
 https://conda.anaconda.org/conda-forge/noarch/sphinx-5.3.0-pyhd8ed1ab_0.tar.bz2#f9e1fcfe235d655900bfeb6aee426472
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.36-pyhd8ed1ab_0.tar.bz2#bff49231f6b67c01a7a89d56ca0693ab
-https://conda.anaconda.org/conda-forge/noarch/ipydatawidgets-4.3.2-pyhc268e32_0.tar.bz2#aff80a4f5dca225740523d330c25c57e
-https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.16.5-pyhd8ed1ab_0.conda#3b3eea0d8676303ff883e7581f30556d
+https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.18.0-pyhd8ed1ab_0.conda#be95d2cc7614462440e4e10b5b373067
 https://conda.anaconda.org/conda-forge/noarch/myst-parser-0.18.1-pyhd8ed1ab_0.tar.bz2#bcfdf5c7d8bf5c6f6be7b4c66fff2eca
 https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.2.7-pyhd8ed1ab_0.conda#b019fe41e6f6b88e0557532514f39cff
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.2-pyhd8ed1ab_0.tar.bz2#40be846cd4e78672a40e43db9dae753c
@@ -326,7 +330,7 @@ https://conda.anaconda.org/conda-forge/noarch/sphinx-autodoc-typehints-1.19.5-py
 https://conda.anaconda.org/conda-forge/noarch/twine-4.0.2-pyhd8ed1ab_0.conda#e3a16168d6b9deefb8c1caa7943fb49e
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.1-pyhd8ed1ab_0.tar.bz2#8a11a646076b72bcaa71328f07c1aaab
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-0.4.8-pyhd8ed1ab_0.tar.bz2#f4f150f83ed90a1b833e6081bbf38257
-https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.7.1-pyhd8ed1ab_0.tar.bz2#f04d31b32fa80c6d97ac1551f7f1f19f
+https://conda.anaconda.org/conda-forge/noarch/pytest-check-links-0.8.0-pyhd8ed1ab_0.conda#639513b3fc51ee25e00a423fa430a2da
 https://conda.anaconda.org/conda-forge/noarch/notebook-6.5.2-pyha770c72_1.tar.bz2#7bf26ca095481f206e6f9dd7681085fe
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-3.5.2-pyhd8ed1ab_0.conda#6c472ca91b5c19138f8706842f0aac14
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab-fonts-2.1.1-pyhd8ed1ab_0.tar.bz2#fc28d40ad8ffa770a870d3c30eac09f2
diff --git a/.github/locks/win-64_lock-environment.conda.lock b/.github/locks/win-64_lock-environment.conda.lock
index bd779bdb..67aa4f87 100644
--- a/.github/locks/win-64_lock-environment.conda.lock
+++ b/.github/locks/win-64_lock-environment.conda.lock
@@ -3,13 +3,14 @@
 #   - nodefaults
 
 # dependencies:
-#   - conda-lock >=1.2,<1.3
+#   - conda-lock >=1.3,<1.4
 #   - mamba >=1.1.0,<1.2
 #   - python >=3.11,<3.12
+#   - conda !=22.11.1
 # dependencies: []
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.9.24-h5b45459_0.tar.bz2#5fba0abc60bf327a4bc4188cd64678be
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
 https://conda.anaconda.org/conda-forge/noarch/pybind11-abi-4-hd8ed1ab_3.tar.bz2#878f923dd6acc8aeb47a75da6c4098be
 https://conda.anaconda.org/conda-forge/win-64/python_abi-3.11-3_cp311.conda#fd1634ba85cfea9376e1fc02d6f592e9
 https://conda.anaconda.org/conda-forge/noarch/tzdata-2022g-h191b570_0.conda#51fc4fcfb19f5d95ffc8c339db5068e8
@@ -25,46 +26,46 @@ https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#
 https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.3-h8ffe710_1.tar.bz2#d12763533276560a931c1bd3df1adf63
 https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-he774522_1000.tar.bz2#d5cf4b7eaa52316f135eed9e8548ad57
 https://conda.anaconda.org/conda-forge/win-64/openssl-3.0.7-hcfcfb64_1.conda#e48b661f57b25ddf34996fa8b685182d
-https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.3-h8ffe710_0.tar.bz2#843a3cd031e593c24b542206c3444a2b
+https://conda.anaconda.org/conda-forge/win-64/reproc-14.2.4-hcfcfb64_0.conda#059e1351c1affff15b16aec51c6967a6
 https://conda.anaconda.org/conda-forge/win-64/tk-8.6.12-h8ffe710_0.tar.bz2#c69a5047cc9291ae40afd4a1ad6f0c0f
 https://conda.anaconda.org/conda-forge/win-64/xz-5.2.6-h8d14728_0.tar.bz2#515d77642eaa3639413c6b1bc3f94219
 https://conda.anaconda.org/conda-forge/win-64/yaml-0.2.5-h8ffe710_2.tar.bz2#adbfb9f45d1004a26763652246a33764
 https://conda.anaconda.org/conda-forge/win-64/yaml-cpp-0.7.0-h63175ca_2.tar.bz2#27c8a78ba0cd18268cfc7b04c5512162
-https://conda.anaconda.org/conda-forge/win-64/krb5-1.19.3-hc8ab02b_0.tar.bz2#729fcb13bda4bbd2dbc0c979dd16e677
-https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.22-h7755175_0.tar.bz2#f782e1756fd2c9b62931e95363e0205a
+https://conda.anaconda.org/conda-forge/win-64/krb5-1.20.1-heb0366b_0.conda#a07b05ee8f451ab15698397185efe989
+https://conda.anaconda.org/conda-forge/win-64/libsolv-0.7.23-h12be248_0.conda#4955aac5971a11e1b79c47912645b9e2
 https://conda.anaconda.org/conda-forge/win-64/libssh2-1.10.0-h9a1e1f7_3.tar.bz2#c2b344e960a173c777bb3ed172c38cd8
 https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.3-hc3477c8_0.tar.bz2#6dcf17bf780618ddb559d992ea3b6961
 https://conda.anaconda.org/conda-forge/win-64/python-3.11.0-hcf16a7b_0_cpython.tar.bz2#13ee3577afc291dabd2d9edc59736688
-https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.3-h0e60522_0.tar.bz2#534e8626893c41ed3b08bbba07396ca3
+https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.4-h63175ca_0.conda#a9ee9bbbbda9b32ec690c4909146770d
 https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h7755175_4.tar.bz2#13acb3626fcc8c0577249f3a7b6129f4
 https://conda.anaconda.org/conda-forge/noarch/appdirs-1.4.4-pyh9f0ad1d_0.tar.bz2#5f095bc6454094e96f146491fd03633b
 https://conda.anaconda.org/conda-forge/noarch/cachy-0.3.0-pyhd8ed1ab_1.tar.bz2#5dfee17f24e2dfd18d7392b48c9351e2
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.9.24-pyhd8ed1ab_0.tar.bz2#f66309b099374af91369e67e84af397d
+https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-2.1.1-pyhd8ed1ab_0.tar.bz2#c1d5b294fbf9a795dec349a6f4d8be8e
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
 https://conda.anaconda.org/conda-forge/noarch/crashtest-0.3.1-pyhd8ed1ab_0.tar.bz2#b8477552274c1cfdb533e954c76523f1
 https://conda.anaconda.org/conda-forge/noarch/distlib-0.3.6-pyhd8ed1ab_0.tar.bz2#b65b4d50dbd2d50fa0aeac367ec9eed7
-https://conda.anaconda.org/conda-forge/noarch/filelock-3.8.2-pyhd8ed1ab_0.conda#0f09c2bc17ddd8732be8e5b99297c7ce
+https://conda.anaconda.org/conda-forge/noarch/filelock-3.9.0-pyhd8ed1ab_0.conda#1addc115923d646ca19ed90edc413506
 https://conda.anaconda.org/conda-forge/noarch/idna-3.4-pyhd8ed1ab_0.tar.bz2#34272b248891bddccc64479f9a7fffed
-https://conda.anaconda.org/conda-forge/win-64/libarchive-3.5.2-habf0b7a_3.tar.bz2#96f14843ac68b6d49d376b2c76018c1a
-https://conda.anaconda.org/conda-forge/win-64/libcurl-7.86.0-heaf79c2_1.tar.bz2#d5fc1cba559c9889332ffb2a39001704
+https://conda.anaconda.org/conda-forge/win-64/libarchive-3.6.2-h27c7867_0.conda#6e1fc6cfaa26186dd5abd5df8d732193
+https://conda.anaconda.org/conda-forge/win-64/libcurl-7.87.0-h68f0423_0.conda#27b5308ff9ea613d99b004cb698c0e2d
 https://conda.anaconda.org/conda-forge/win-64/markupsafe-2.1.1-py311ha68e1ae_2.tar.bz2#d782a70b46000ea9a3c5c69c5fe0f767
 https://conda.anaconda.org/conda-forge/win-64/menuinst-1.4.19-py311h1ea47a8_1.tar.bz2#8eb00075c8acb7dd264c4a8537b89549
 https://conda.anaconda.org/conda-forge/noarch/more-itertools-9.0.0-pyhd8ed1ab_0.tar.bz2#9b6ad26944f19f599800b068e0582227
 https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.0.4-py311h005e61a_1.tar.bz2#ef561ef7fcf37af359d9cb424a6346c1
+https://conda.anaconda.org/conda-forge/noarch/packaging-22.0-pyhd8ed1ab_0.conda#0e8e1bd93998978fc3125522266d12db
 https://conda.anaconda.org/conda-forge/noarch/pastel-0.2.1-pyhd8ed1ab_0.tar.bz2#a4eea5bff523f26442405bc5d1f52adb
-https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.2-pyhd8ed1ab_0.conda#8fb2779f1ab2ce91e893f31a36fbcbfa
-https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.5.2-pyhd8ed1ab_1.tar.bz2#2fb3f88922e7aec26ba652fcdfe13950
+https://conda.anaconda.org/conda-forge/noarch/pkginfo-1.9.3-pyhd8ed1ab_0.conda#d08b45500011bfb2dd5ed5d9e4794272
 https://conda.anaconda.org/conda-forge/win-64/pycosat-0.6.4-py311ha68e1ae_1.tar.bz2#c7af04cd8a66f6d782982751200239d0
 https://conda.anaconda.org/conda-forge/noarch/pycparser-2.21-pyhd8ed1ab_0.tar.bz2#076becd9e05608f8dc72757d5f3a91ff
 https://conda.anaconda.org/conda-forge/noarch/pylev-1.4.0-pyhd8ed1ab_0.tar.bz2#edf8651c4379d9d1495ad6229622d150
-https://conda.anaconda.org/conda-forge/noarch/pyparsing-3.0.9-pyhd8ed1ab_0.tar.bz2#e8fbc1b54b25f4b08281467bc13b70cc
 https://conda.anaconda.org/conda-forge/win-64/pywin32-ctypes-0.2.0-py311h1ea47a8_1006.tar.bz2#86ee973a16f5449d9ded34b512331dce
 https://conda.anaconda.org/conda-forge/win-64/pyyaml-6.0-py311ha68e1ae_5.tar.bz2#0c97d59d54eb52e170224b3de6ade906
 https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml.clib-0.2.7-py311ha68e1ae_1.conda#654fbe603c79490699cd7447e4627aee
 https://conda.anaconda.org/conda-forge/win-64/ruamel_yaml-0.15.80-py311ha68e1ae_1008.tar.bz2#c1c3cca1078977cfa12d36f32eb58fbe
-https://conda.anaconda.org/conda-forge/noarch/setuptools-65.5.1-pyhd8ed1ab_0.tar.bz2#cfb8dc4d9d285ca5fb1177b9dd450e33
+https://conda.anaconda.org/conda-forge/noarch/setuptools-65.6.3-pyhd8ed1ab_0.conda#9600fc9524d3f821e6a6d58c52f5bf5a
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
+https://conda.anaconda.org/conda-forge/noarch/smmap-3.0.5-pyh44b312d_0.tar.bz2#3a8dc70789709aa315325d5df06fb7e4
 https://conda.anaconda.org/conda-forge/noarch/tomli-2.0.1-pyhd8ed1ab_0.tar.bz2#5844808ffab9ebdb694585b50ba02a96
 https://conda.anaconda.org/conda-forge/noarch/toolz-0.12.0-pyhd8ed1ab_0.tar.bz2#92facfec94bc02d6ccf42e7173831a36
 https://conda.anaconda.org/conda-forge/noarch/typing-3.10.0.0-pyhd8ed1ab_0.tar.bz2#e6573ac68718f17b9d4f5c8eda3190f2
@@ -72,35 +73,37 @@ https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.4.0-pyha770c72
 https://conda.anaconda.org/conda-forge/noarch/webencodings-0.5.1-py_1.tar.bz2#3563be4c5611a44210d9ba0c16113136
 https://conda.anaconda.org/conda-forge/noarch/win_inet_pton-1.1.0-pyhd8ed1ab_6.tar.bz2#30878ecc4bd36e8deeea1e3c151b2e0b
 https://conda.anaconda.org/conda-forge/noarch/zipp-3.11.0-pyhd8ed1ab_0.conda#09b5b885341697137879a4f039a9e5a1
-https://conda.anaconda.org/conda-forge/win-64/cffi-1.15.1-py311h7d9ee11_2.tar.bz2#ef9993d38b7be752453fc70d7bd81d4b
+https://conda.anaconda.org/conda-forge/win-64/cffi-1.15.1-py311h7d9ee11_3.conda#a8524727eb956b4741e25a64af79edb8
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-win_pyhd8ed1ab_2.tar.bz2#6b58680207b526c42dcff68b543803dd
 https://conda.anaconda.org/conda-forge/noarch/clikit-0.6.2-pyh9f0ad1d_0.tar.bz2#159273f717a11e53b2656f8b6521a5e2
+https://conda.anaconda.org/conda-forge/noarch/gitdb-4.0.10-pyhd8ed1ab_0.conda#3706d2f3d7cb5dae600c833345a76132
 https://conda.anaconda.org/conda-forge/noarch/html5lib-1.1-pyh9f0ad1d_0.tar.bz2#b2355343d6315c892543200231d7154a
-https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-5.1.0-pyha770c72_0.conda#46a62e35b9ae515cf0e49afc7fe0e7ef
+https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.0.0-pyha770c72_0.conda#691644becbcdca9f73243450b1c63e62
 https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.tar.bz2#31e4a1506968d017229bdb64695013a1
 https://conda.anaconda.org/conda-forge/noarch/jinja2-3.1.2-pyhd8ed1ab_1.tar.bz2#c8490ed5c70966d232fdd389d0dbed37
-https://conda.anaconda.org/conda-forge/win-64/libmamba-1.1.0-hd18bbca_2.conda#672850850275c7f10001328b65ae297b
-https://conda.anaconda.org/conda-forge/noarch/packaging-21.3-pyhd8ed1ab_0.tar.bz2#71f1ab2de48613876becddd496371c85
+https://conda.anaconda.org/conda-forge/win-64/libmamba-1.1.0-h8a7d157_3.conda#eca3e8148e2d03ffcf0dc71811cf7b94
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2#56cd9fe388baac0e90c7149cfac95b60
 https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.17.21-py311ha68e1ae_2.tar.bz2#7a451146b0fc585db0930ca0ad389f8e
 https://conda.anaconda.org/conda-forge/noarch/tomlkit-0.11.6-pyha770c72_0.tar.bz2#471bf9e605820b59988e830382b8d654
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.4.0-hd8ed1ab_0.tar.bz2#be969210b61b897775a0de63cd9e9026
-https://conda.anaconda.org/conda-forge/win-64/virtualenv-20.17.0-py311h1ea47a8_0.conda#ae06f1b15c37af3a5bc4efcafef2534e
 https://conda.anaconda.org/conda-forge/win-64/brotlipy-0.7.0-py311ha68e1ae_1005.tar.bz2#dd9604ece454103e7210110c6d343e37
 https://conda.anaconda.org/conda-forge/noarch/click-default-group-1.2.2-pyhd8ed1ab_1.tar.bz2#72a46ffc25701c173932fd55cf0965d3
-https://conda.anaconda.org/conda-forge/win-64/cryptography-38.0.4-py311h28e9c30_0.conda#369bad555cfdd4094409411ac563de32
-https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-5.1.0-hd8ed1ab_0.conda#3dc2248927de739b4d2e2da9a9972bfe
-https://conda.anaconda.org/conda-forge/win-64/libmambapy-1.1.0-py311h29ee5fe_2.conda#132120486e4ce925c06ceffa950a204c
-https://conda.anaconda.org/conda-forge/win-64/pydantic-1.10.2-py311ha68e1ae_1.tar.bz2#fed64316d6ff7ca98e21f4c365e2bf64
+https://conda.anaconda.org/conda-forge/win-64/cryptography-39.0.0-py311h28e9c30_0.conda#9e2a95fcaa6333eac22a51f2beb913ee
+https://conda.anaconda.org/conda-forge/noarch/gitpython-3.1.30-pyhd8ed1ab_0.conda#0c217ab2f5ef6925e4e52c70b57cfc4a
+https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.0.0-hd8ed1ab_0.conda#a67d43e1527a37199dd8db913366f68e
+https://conda.anaconda.org/conda-forge/win-64/libmambapy-1.1.0-py311h29ee5fe_3.conda#578de8993499c1436875075c2b4bd6b6
+https://conda.anaconda.org/conda-forge/noarch/platformdirs-2.6.2-pyhd8ed1ab_0.conda#0b4cc3f8181b0d8446eb5387d7848a54
+https://conda.anaconda.org/conda-forge/win-64/pydantic-1.10.4-py311ha68e1ae_0.conda#525c3930015c4284c2d389dec238f043
 https://conda.anaconda.org/conda-forge/win-64/zstandard-0.19.0-py311he5d195f_1.conda#af889af78c5389e344392e305b4d7bc7
 https://conda.anaconda.org/conda-forge/noarch/conda-package-streaming-0.7.0-pyhd8ed1ab_1.conda#1a2fa9e53cfbc2e4d9ab21990805a436
-https://conda.anaconda.org/conda-forge/win-64/keyring-23.11.0-py311h1ea47a8_0.tar.bz2#bac148b3eb51d1d1b6654256162d1b16
-https://conda.anaconda.org/conda-forge/noarch/pyopenssl-22.1.0-pyhd8ed1ab_0.tar.bz2#fbfa0a180d48c800f922a10a114a8632
+https://conda.anaconda.org/conda-forge/win-64/keyring-23.13.1-py311h1ea47a8_0.conda#ff14a49b769ea59ee6709a890e17f317
+https://conda.anaconda.org/conda-forge/noarch/pyopenssl-23.0.0-pyhd8ed1ab_0.conda#d41957700e83bbb925928764cb7f8878
+https://conda.anaconda.org/conda-forge/win-64/virtualenv-20.17.1-py311h1ea47a8_0.conda#b758084a6113e2266912b3058391b6c4
 https://conda.anaconda.org/conda-forge/noarch/conda-package-handling-2.0.2-pyh38be061_0.conda#44800e9bd13143292097c65e57323038
 https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.13-pyhd8ed1ab_0.conda#3078ef2359efd6ecadbc7e085c5e0592
 https://conda.anaconda.org/conda-forge/noarch/requests-2.28.1-pyhd8ed1ab_1.tar.bz2#089382ee0e2dc2eae33a04cc3c2bddb0
-https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.12-pyhd8ed1ab_1.tar.bz2#e4b40ac0d53e81ebf8892e3b3ca9c1cf
+https://conda.anaconda.org/conda-forge/noarch/cachecontrol-0.12.11-pyhd8ed1ab_0.tar.bz2#6eefee9888f33f150b5d44d616b1a613
 https://conda.anaconda.org/conda-forge/win-64/conda-22.9.0-py311h1ea47a8_2.tar.bz2#b10f47d78cb51f295ee9e6f3a611fa17
 https://conda.anaconda.org/conda-forge/noarch/ensureconda-1.4.3-pyhd8ed1ab_0.tar.bz2#c99ae3abf501990769047b4b40a98f17
-https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.2.1-pyhd8ed1ab_1.tar.bz2#7b1dde4760c5c554523fead6c2771af2
-https://conda.anaconda.org/conda-forge/win-64/mamba-1.1.0-py311h8cb466b_2.conda#599310eb70e058ed0fea0147fc0775ca
+https://conda.anaconda.org/conda-forge/noarch/conda-lock-1.3.0-pyhd8ed1ab_0.conda#1165b4b0171fad7555822fe3a85365ed
+https://conda.anaconda.org/conda-forge/win-64/mamba-1.1.0-py311h8cb466b_3.conda#256c2620140f8f9656c13c06005abf31
diff --git a/docs/conf.py b/docs/conf.py
index 9140a220..ad5bbbe5 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -1,6 +1,6 @@
 """ documentation for ipyforcegraph
 """
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 
diff --git a/dodo.py b/dodo.py
index e8962d18..d1b0e92e 100644
--- a/dodo.py
+++ b/dodo.py
@@ -7,7 +7,7 @@
     See `doit list` for more options.
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import os
diff --git a/examples/3D.ipynb b/examples/3D.ipynb
index 8dcd2e7c..0a9e0ccb 100644
--- a/examples/3D.ipynb
+++ b/examples/3D.ipynb
@@ -5,7 +5,7 @@
    "id": "a90e6ee8-422c-4c82-8945-a78ec51a4c28",
    "metadata": {},
    "source": [
-    "# 🪩 3D"
+    "# 🔮 3D"
    ]
   },
   {
@@ -22,72 +22,71 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "32dcf622-cd7e-41e7-8658-f31d4db9ce37",
+   "id": "e6accf09-c655-4868-b7d9-dde0eb24b0a2",
    "metadata": {},
    "outputs": [],
    "source": [
-    "import random\n",
-    "\n",
-    "import ipywidgets as W\n",
-    "import networkx as nx\n",
-    "import numpy as np\n",
-    "\n",
-    "from ipyforcegraph.forcegraph import ForceGraph3D"
+    "with __import__(\"importnb\").Notebook():\n",
+    "    from _index import make_a_simple_example\n",
+    "    from Behaviors import add_node_labels, add_node_selection"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "5f8faea8-cca6-41ee-8d29-ec3a63c5b7cc",
-   "metadata": {
-    "tags": []
-   },
+   "id": "6fb9bb66-13c5-4566-acc0-b9052d3b6f40",
+   "metadata": {},
    "outputs": [],
    "source": [
-    "fg3 = ForceGraph3D()\n",
-    "fg3"
+    "from ipyforcegraph.forcegraph import ForceGraph3D\n",
+    "\n",
+    "\n",
+    "def make_a_full_3d_example():\n",
+    "    fg, box = make_a_simple_example(GraphClass=ForceGraph3D)\n",
+    "    add_node_selection(fg, box)\n",
+    "    add_node_labels(fg, box)\n",
+    "    return fg, box"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "ae9a7e52-c687-408c-92d7-ab964aa44196",
-   "metadata": {},
+   "id": "cbfa0010-6553-41e3-a9c9-80b59d1c89fa",
+   "metadata": {
+    "jupyter": {
+     "source_hidden": true
+    },
+    "slideshow": {
+     "slide_type": "slide"
+    },
+    "tags": []
+   },
    "outputs": [],
    "source": [
-    "atlas = nx.graph_atlas_g()"
+    "if __name__ == \"__main__\":\n",
+    "    fg, box = make_a_full_3d_example()\n",
+    "    display(box)"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "1063aeed-61c4-4439-8d24-e1c04adda0ac",
+   "cell_type": "markdown",
+   "id": "1f772135-46af-4b14-b648-941522c78983",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "def update_graph(i: int = None) -> None:\n",
-    "    G = atlas[i if i is not None else random.randint(0, len(atlas))]\n",
-    "    nodes = list(G.nodes)\n",
-    "    fg3.source.nodes.array = np.array(nodes, dtype=np.int32)\n",
-    "    fg3.source.links.array = np.array(\n",
-    "        [[nodes.index(source), nodes.index(target)] for source, target in G.edges],\n",
-    "        dtype=np.int32,\n",
-    "    )\n",
-    "\n",
-    "\n",
-    "update_graph()"
+    "```{warning}\n",
+    "Currently, some of the mouse behavior handlers are conflicting with the JupyterLab defaults.\n",
+    "```"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "36906fb0-51d5-42b4-9710-e5b327d1fb9d",
+   "cell_type": "markdown",
+   "id": "5af10943-c2aa-41cd-a1ec-659745d350ce",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "@W.interact\n",
-    "def g(i=(0, len(atlas) - 1)):\n",
-    "    update_graph(i)"
+    "```{hint}\n",
+    "A future revision may move the 3d renderer (and potentially the 2d renderer) into dedicated `iframe` elements\n",
+    "to provide a more consistent and robust experience, especially for large graphs.\n",
+    "```"
    ]
   }
  ],
diff --git a/examples/Behaviors.ipynb b/examples/Behaviors.ipynb
index 49673a1c..37b05787 100644
--- a/examples/Behaviors.ipynb
+++ b/examples/Behaviors.ipynb
@@ -22,88 +22,154 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "2ed72b41-c238-48d4-add1-dd918d70a646",
+   "id": "9f3f85fe-a0a9-4086-992e-2ca1552f07b8",
    "metadata": {},
    "outputs": [],
    "source": [
-    "import random\n",
-    "\n",
     "import ipywidgets as W\n",
-    "import networkx as nx\n",
-    "import numpy as np\n",
-    "\n",
-    "from ipyforcegraph.behaviors import NodeSelection\n",
-    "from ipyforcegraph.forcegraph import ForceGraph"
+    "import traitlets as T"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "38280a14-ef4b-451b-be64-cf541cb254e1",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "with __import__(\"importnb\").Notebook():\n",
+    "    from _index import make_a_simple_example"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "833c749b-8ba2-4db7-8bfc-3bd3a2cc969f",
+   "metadata": {},
+   "source": [
+    "```{hint}\n",
+    "After rendering the cell below, select _Create New View For Output_ from the output's right-click menu to see more things added\n",
+    "```"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "5aed228a-cfae-452d-bdd3-cb3437dac802",
+   "id": "a2532791-3a00-4715-ae2d-1b66ea88758f",
    "metadata": {
     "tags": []
    },
    "outputs": [],
    "source": [
-    "fg = ForceGraph(behaviors=[NodeSelection()])\n",
-    "fg"
+    "if __name__ == \"__main__\":\n",
+    "    fg, box = make_a_simple_example()\n",
+    "    display(box)"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "14d08341-d9bc-4fcb-8574-5fb268afa1e2",
+   "cell_type": "markdown",
+   "id": "cccd2fcb-4b03-403c-8371-6cc51bd984c2",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "atlas = nx.graph_atlas_g()"
+    "## `NodeSelection`\n",
+    "\n",
+    "The `NodeSelection` behavior allows for selecting one or more nodes from the browser, or\n",
+    "updating from the kernel."
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "85c983b4-8761-4838-a790-e23038b5eb77",
+   "id": "ae7d15a9-2a6e-476c-909e-e28e4d9809cd",
    "metadata": {},
    "outputs": [],
    "source": [
-    "def update_graph(i: int = None) -> None:\n",
-    "    G = atlas[i if i is not None else random.randint(0, len(atlas))]\n",
-    "    nodes = list(G.nodes)\n",
-    "    fg.source.nodes.array = np.array(nodes, dtype=np.int32)\n",
-    "    fg.source.links.array = np.array(\n",
-    "        [[nodes.index(source), nodes.index(target)] for source, target in G.edges],\n",
-    "        dtype=np.int32,\n",
-    "    )"
+    "from ipyforcegraph.behaviors import NodeSelection\n",
+    "\n",
+    "\n",
+    "def add_node_selection(fg=None, box=None):\n",
+    "    if fg is None:\n",
+    "        fg, box = make_a_simple_example()\n",
+    "    selection = NodeSelection()\n",
+    "    fg.behaviors = [selection]\n",
+    "    ui_selection = W.TagsInput(\n",
+    "        placeholder=\"select some nodes\",\n",
+    "        description=\"selected\",\n",
+    "        allowed_tags=sorted(fg.source.nodes.id),\n",
+    "        layout=dict(max_width=\"500px\"),\n",
+    "    )\n",
+    "    T.link((selection, \"selected\"), (ui_selection, \"value\"))\n",
+    "    box.children[1].children += (ui_selection,)\n",
+    "    return fg, box"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "ca340789-9b0a-4d27-91fa-520dda665b22",
+   "id": "d4de87e4-6c4f-43c2-9802-bef3d4e68b48",
    "metadata": {},
    "outputs": [],
    "source": [
-    "@W.interact\n",
-    "def g(i=(0, len(atlas) - 1)):\n",
-    "    update_graph(i)"
+    "if __name__ == \"__main__\":\n",
+    "    add_node_selection(fg, box)\n",
+    "    display(box)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "4cb62bb8-b122-4e5d-b8fb-04bab2c127df",
+   "metadata": {},
+   "source": [
+    "```{hint}\n",
+    "Note that the nodes changed colors. Click a node to select it, or use <kbd>ctrl</kbd> or <kbd>shift</kbd> to select multiple nodes.\n",
+    "```"
    ]
   },
   {
    "cell_type": "markdown",
-   "id": "5062cc2a-950c-4396-84cb-92e609def322",
+   "id": "615dba57-a08f-45a4-bd60-5d04519c5075",
    "metadata": {},
    "source": [
-    "The data can be set from the kernel."
+    "The selection is handed back from the client, and can be used with other widgets."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "96990557-2450-4600-889e-d6e19fa72909",
+   "metadata": {},
+   "source": [
+    "## `NodeLabels`\n",
+    "\n",
+    "Node labels can be revealed when hovering over the node. By default the node's `id`\n",
+    "column will be used."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "478848d8-a8cd-4aed-a6cb-314464cbaea5",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from ipyforcegraph.behaviors import NodeLabels\n",
+    "\n",
+    "\n",
+    "def add_node_labels(fg=None, box=None):\n",
+    "    node_labels = NodeLabels()\n",
+    "    if fg is None:\n",
+    "        fg, box = make_a_simple_example()\n",
+    "    fg.behaviors += (node_labels,)"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "c823b7ba-e65f-40e9-af34-b3d37d040445",
+   "id": "4a1e78bb-e851-4c25-a15b-aa2bc40051e3",
    "metadata": {},
    "outputs": [],
    "source": [
-    "fg.behaviors[0].value.array = np.array([1, 2, 3], dtype=np.int32)"
+    "if __name__ == \"__main__\":\n",
+    "    add_node_labels(fg, box)\n",
+    "    display(box)"
    ]
   }
  ],
diff --git a/examples/_index.ipynb b/examples/_index.ipynb
index 905346b0..7d273ddd 100644
--- a/examples/_index.ipynb
+++ b/examples/_index.ipynb
@@ -4,7 +4,13 @@
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "# IPyForceGraph 🚀"
+    "# IPyForceGraph 🚀\n",
+    "\n",
+    "`ipyforcegraph` wraps [force-graph] and [3d-force-graph] for data-driven views of graphs\n",
+    "with up to a few thousand nodes with composable behaviors.\n",
+    "\n",
+    "[3d-force-graph]: https://github.com/vasturiano/force-graph\n",
+    "[force-graph]: https://github.com/vasturiano/force-graph"
    ]
   },
   {
@@ -27,28 +33,15 @@
     "from pathlib import Path\n",
     "\n",
     "import ipywidgets as W\n",
-    "import numpy as np\n",
     "\n",
-    "import ipyforcegraph.forcegraph"
+    "from ipyforcegraph.forcegraph import DataFrameSource, ForceGraph"
    ]
   },
   {
    "cell_type": "markdown",
    "metadata": {},
    "source": [
-    "## Using `ndarray`s\n",
-    "\n",
-    "We have some sample data in various formats. In its simplest form, `ForceGraph` will\n",
-    "only use NumPy `ndarray`s for its source data."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "data = json.loads(Path(\"datasets/miserables.json\").read_text())"
+    "## A Simple Example"
    ]
   },
   {
@@ -57,7 +50,15 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "data[\"nodes\"][0]"
+    "def make_a_simple_example(\n",
+    "    source=None, dataset=\"datasets/miserables.json\", GraphClass=ForceGraph\n",
+    "):\n",
+    "    if source is None:\n",
+    "        data = json.loads(Path(dataset).read_text())\n",
+    "        source = DataFrameSource(**data)\n",
+    "    fg = GraphClass(source=source, layout=dict(height=\"500px\"))\n",
+    "    box = W.HBox([fg, W.VBox([])])\n",
+    "    return fg, box"
    ]
   },
   {
@@ -66,22 +67,24 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "node_ids = [n[\"id\"] for n in data[\"nodes\"]]\n",
-    "links = [\n",
-    "    [node_ids.index(l[\"source\"]), node_ids.index(l[\"target\"])] for l in data[\"links\"]\n",
-    "]"
+    "if __name__ == \"__main__\":\n",
+    "    fg, box = make_a_simple_example()\n",
+    "    display(box)"
    ]
   },
   {
-   "cell_type": "code",
-   "execution_count": null,
+   "cell_type": "markdown",
    "metadata": {},
-   "outputs": [],
    "source": [
-    "fg = ipyforcegraph.forcegraph.ForceGraph()\n",
-    "fg.source.nodes.array = np.linspace(0, len(data[\"nodes\"]), dtype=np.int32)\n",
-    "fg.source.links.array = np.array(links, dtype=np.int32)\n",
-    "fg"
+    "## Data Formats\n",
+    "\n",
+    "Some sample data in various formats are included. The simplest form expects two\n",
+    "`DataFrame`-like structures:\n",
+    "\n",
+    "- `nodes` should contain an `id` field of type `str` or `int`\n",
+    "  - if missing, the node's row index in the columns will be used\n",
+    "- `links` should contain `source` and `target` columns, and may refer to either the `id`\n",
+    "  or row index"
    ]
   },
   {
@@ -91,8 +94,7 @@
     "# Read more\n",
     "\n",
     "- [👟 Behaviors](./Behaviors.ipynb)\n",
-    "- [🪩 3D](./3D.ipynb)\n",
-    "- [🐛 Debugging with `FORCEGRAPH_DEBUG`](./FORCEGRAPH_DEBUG.ipynb)"
+    "- [🔮 3D](./3D.ipynb)"
    ]
   }
  ],
diff --git a/examples/FORCEGRAPH_DEBUG.ipynb b/examples/future/FORCEGRAPH_DEBUG.ipynb
similarity index 52%
rename from examples/FORCEGRAPH_DEBUG.ipynb
rename to examples/future/FORCEGRAPH_DEBUG.ipynb
index 343b5818..c9b48618 100644
--- a/examples/FORCEGRAPH_DEBUG.ipynb
+++ b/examples/future/FORCEGRAPH_DEBUG.ipynb
@@ -34,23 +34,78 @@
     "import ipywidgets as W\n",
     "import networkx as nx\n",
     "import numpy as np\n",
+    "import pandas as pd\n",
     "\n",
     "from ipyforcegraph.behaviors import NodeSelection\n",
-    "from ipyforcegraph.forcegraph import ForceGraph"
+    "from ipyforcegraph.forcegraph import DataFrameSource, ForceGraph"
    ]
   },
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "8377b0ba-dacf-494c-8cd9-1b0992abd461",
+   "id": "a6c86e06-2620-4e9a-972d-c6b37873ee3d",
    "metadata": {
     "tags": []
    },
    "outputs": [],
    "source": [
-    "fg = ForceGraph(behaviors=[NodeSelection()])\n",
+    "df_nodes = pd.DataFrame([{\"label\": f\"node {i}\"} for i in range(10000)])\n",
+    "df_nodes.shape"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3ac33127-5b65-47c8-a6f6-7c8b10e0c213",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "df_links = pd.DataFrame(\n",
+    "    [\n",
+    "        {\n",
+    "            \"source\": random.randint(0, 9999),\n",
+    "            \"target\": random.randint(0, 9999),\n",
+    "        }\n",
+    "        for i in range(9999)\n",
+    "    ]\n",
+    ")\n",
+    "df_links.shape"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e2f81df2-6c7f-47d5-9cc7-d40ee8f2dc49",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "source = DataFrameSource(nodes=df_nodes, links=df_links)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7f875b01-ecb2-4350-acb1-700465b9e5c7",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "fg = ForceGraph(source=source)\n",
     "fg"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7f27cb34-78fd-4e8d-938b-8916369f23da",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "fg.source.links"
+   ]
   }
  ],
  "metadata": {
diff --git a/examples/future/NetworkX.ipynb b/examples/future/NetworkX.ipynb
new file mode 100644
index 00000000..bf1cf08a
--- /dev/null
+++ b/examples/future/NetworkX.ipynb
@@ -0,0 +1,107 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "53472575-4bb7-4445-83d9-751230fab966",
+   "metadata": {},
+   "source": [
+    "## TODO: restore with better examples"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b40c7581-8c73-4937-aefe-4dd2937856b0",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "atlas = nx.graph_atlas_g()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "d84eafe5-0c45-4804-92e5-2a73aea568b2",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def update_graph(\n",
+    "    i: int = None,\n",
+    "    selected_color=None,\n",
+    "    not_selected_color=None,\n",
+    ") -> None:\n",
+    "    G = atlas[i if i is not None else random.randint(0, len(atlas))]\n",
+    "    nodes = list(G.nodes)\n",
+    "    with fg.source.hold_sync(), selection.hold_sync():\n",
+    "        fg.source.nodes = pd.DataFrame([{\"label\": f\"Node {i}\"} for i in nodes])\n",
+    "        fg.source.links = pd.DataFrame(\n",
+    "            {\"source\": nodes.index(source), \"target\": nodes.index(target)}\n",
+    "            for source, target in G.edges\n",
+    "        )\n",
+    "        selection.selected_color = selected_color or \"#B3A369\"\n",
+    "        selection.not_selected_color = not_selected_color or \"#003057\"\n",
+    "\n",
+    "\n",
+    "update_graph()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1485d518-6349-4e37-ae31-16a78a99ac20",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "@W.interact(\n",
+    "    selected_color=W.ColorPicker(value=\"#B3A369\", description=\"selected\"),\n",
+    "    not_selected_color=W.ColorPicker(value=\"#003057\", description=\"not selected\"),\n",
+    ")\n",
+    "def g(\n",
+    "    selected_color,\n",
+    "    not_selected_color,\n",
+    "    i=(0, len(atlas) - 1),\n",
+    "):\n",
+    "    update_graph(i, selected_color)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "bd1638ed-1901-4c9f-95b9-7e7a5c3786f8",
+   "metadata": {},
+   "source": [
+    "The selected nodes can be set from the kernel."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "cf9e12e1-7c6e-4df1-be2f-6f4a527b1e01",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "selection.selected = [1, 2, 3]"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.11.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/js/index.ts b/js/index.ts
index 53cc24cf..e2bc5f2a 100644
--- a/js/index.ts
+++ b/js/index.ts
@@ -1,7 +1,8 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
 
 export * from './tokens';
 export * from './widgets';
+export * from './widgets/serializers';
diff --git a/js/plugin.ts b/js/plugin.ts
index 1c9c502f..433defa9 100644
--- a/js/plugin.ts
+++ b/js/plugin.ts
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
 import { Application, IPlugin } from '@lumino/application';
@@ -37,6 +37,8 @@ const plugin: IPlugin<Application<Widget>, void> = {
         }
 
         loadingWidgets = new PromiseDelegate();
+        const { initializeZstd } = await import('./widgets/serializers');
+        await initializeZstd();
 
         DEBUG && console.warn(`${EMOJI} loading widgets`);
         widgetExports = {
diff --git a/js/schema/forcegraph_schema.ts b/js/schema/forcegraph_schema.ts
index 7dd0d3c5..42073f82 100644
--- a/js/schema/forcegraph_schema.ts
+++ b/js/schema/forcegraph_schema.ts
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
 import { GraphData } from 'force-graph';
diff --git a/js/tokens.ts b/js/tokens.ts
index 91598d77..d9be1b73 100644
--- a/js/tokens.ts
+++ b/js/tokens.ts
@@ -1,8 +1,8 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-import type { ForceGraphInstance, GraphData } from 'force-graph';
+import type { GraphData } from 'force-graph';
 
 import type { ISignal } from '@lumino/signaling';
 
@@ -18,6 +18,17 @@ export const EMPTY_GRAPH_DATA: GraphData = Object.freeze({
   nodes: [],
 });
 
+export const DEFAULT_COLUMNS = {
+  id: 'id',
+  source: 'source',
+  target: 'target',
+};
+
+export const DEFAULT_COLORS = {
+  selected: '#B3A369',
+  notSelected: '#003057',
+};
+
 export const WIDGET_DEFAULTS = {
   _model_module: NAME,
   _model_module_version: VERSION,
@@ -30,9 +41,10 @@ export interface IBehave {
   updateRequested: ISignal<IBehave, void>;
 }
 
-export interface IHasGraph {
-  graph: ForceGraphInstance;
+export interface IHasGraph<T = any> {
+  graph: T;
   source: ISource;
+  rendered: Promise<void>;
 }
 
 export interface ISource {
diff --git a/js/widgets/behavior.ts b/js/widgets/behavior.ts
deleted file mode 100644
index 2516aca4..00000000
--- a/js/widgets/behavior.ts
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2022 ipyforcegraph contributors.
- * Distributed under the terms of the Modified BSD License.
- */
-import ndarray from 'ndarray';
-
-import { ISignal, Signal } from '@lumino/signaling';
-
-import { WidgetModel, unpack_models as deserialize } from '@jupyter-widgets/base';
-
-import { IBehave, IHasGraph, WIDGET_DEFAULTS } from '../tokens';
-
-const SELECTED_COLOR = '#B3A369';
-const NOT_SELECTED_COLOR = '#003057';
-
-export class BehaviorModel extends WidgetModel implements IBehave {
-  protected _updateRequested: Signal<IBehave, void>;
-
-  initialize(attributes: any, options: any) {
-    super.initialize(attributes, options);
-    this._updateRequested = new Signal(this);
-  }
-
-  get updateRequested(): ISignal<IBehave, void> {
-    return this._updateRequested;
-  }
-
-  onUpdate(hasGraph: IHasGraph) {
-    throw new Error('unimplemented');
-  }
-}
-
-/**
- * A model which wraps an `ndarray.NdArray` of indices in `force-graph.GraphData.nodes`.
- */
-export class NodeSelectionModel extends BehaviorModel {
-  static model_name = 'NodeSelectionModel';
-  static serializers = {
-    ...WidgetModel.serializers,
-    value: { deserialize },
-  };
-
-  protected _graph: IHasGraph | null = null;
-
-  defaults() {
-    return {
-      ...super.defaults(),
-      ...WIDGET_DEFAULTS,
-      _model_name: NodeSelectionModel.model_name,
-      value: null,
-      multiple: true,
-    };
-  }
-
-  initialize(attributes: any, options: any) {
-    super.initialize(attributes, options);
-    this.on('change:value', this.onValueChange, this);
-    this.onValueChange();
-  }
-
-  onValueChange(change?: any) {
-    let value = this.get('value');
-    if (value) {
-      value.on('change:array', this.onKernelData, this);
-      this.onKernelData();
-    }
-  }
-
-  onKernelData() {
-    this._updateRequested.emit(void 0);
-  }
-
-  get selected(): Set<number> {
-    let value = this.get('value');
-    return new Set<number>([...(value.get('array')?.data || [])]);
-  }
-
-  set selected(selected: Set<number>) {
-    let value = this.get('value');
-    const newArray = ndarray(new Int32Array([...selected]), [selected.size]);
-    value.set({ array: newArray });
-    value.save_changes();
-  }
-
-  registerGraph(hasGraph: IHasGraph): void {
-    this._graph = hasGraph;
-    hasGraph.graph.onNodeClick((node, event) => {
-      let { selected } = this;
-      const id = node.id as number;
-      if (this.get('multiple') && (event.ctrlKey || event.shiftKey || event.altKey)) {
-        selected.has(id) ? selected.delete(id) : selected.add(id);
-      } else {
-        selected.clear();
-        selected.add(id);
-      }
-
-      this.selected = selected;
-    });
-  }
-
-  onUpdate(hasGraph: IHasGraph) {
-    if (hasGraph !== this._graph) {
-      this.registerGraph(hasGraph);
-    }
-
-    const { selected } = this;
-
-    hasGraph.graph.nodeColor((node) => {
-      return selected.has(node.id as number) ? SELECTED_COLOR : NOT_SELECTED_COLOR;
-    });
-  }
-}
diff --git a/js/widgets/behaviors/base.ts b/js/widgets/behaviors/base.ts
new file mode 100644
index 00000000..ff85ba8b
--- /dev/null
+++ b/js/widgets/behaviors/base.ts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import { ISignal, Signal } from '@lumino/signaling';
+
+import { WidgetModel } from '@jupyter-widgets/base';
+
+import { IBehave, IHasGraph } from '../../tokens';
+
+export class BehaviorModel extends WidgetModel implements IBehave {
+  protected _updateRequested: Signal<IBehave, void>;
+
+  initialize(attributes: any, options: any) {
+    super.initialize(attributes, options);
+    this._updateRequested = new Signal(this);
+  }
+
+  get updateRequested(): ISignal<IBehave, void> {
+    return this._updateRequested;
+  }
+
+  onUpdate(hasGraph: IHasGraph) {
+    throw new Error('unimplemented');
+  }
+}
diff --git a/js/widgets/behaviors/index.ts b/js/widgets/behaviors/index.ts
new file mode 100644
index 00000000..d60c22c5
--- /dev/null
+++ b/js/widgets/behaviors/index.ts
@@ -0,0 +1,7 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+export * from './base';
+export * from './selection';
+export * from './labels';
diff --git a/js/widgets/behaviors/labels.ts b/js/widgets/behaviors/labels.ts
new file mode 100644
index 00000000..416d5457
--- /dev/null
+++ b/js/widgets/behaviors/labels.ts
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import { NodeObject } from 'force-graph';
+
+import { WidgetModel, unpack_models as deserialize } from '@jupyter-widgets/base';
+
+import { IHasGraph, WIDGET_DEFAULTS } from '../../tokens';
+
+import { BehaviorModel } from './base';
+
+export class NodeLabelModel extends BehaviorModel {
+  static model_name = 'NodeLabelModel';
+  static serializers = {
+    ...WidgetModel.serializers,
+    value: { deserialize },
+  };
+
+  protected _graph: IHasGraph | null = null;
+
+  defaults() {
+    return {
+      ...super.defaults(),
+      ...WIDGET_DEFAULTS,
+      _model_name: NodeLabelModel.model_name,
+      column_name: null,
+      default_label: null,
+    };
+  }
+
+  get columnName(): string | null {
+    let columnName = this.get('column_name');
+    if (columnName == null && this._graph) {
+      try {
+        columnName = (this._graph.source as any).get('node_id_column');
+      } catch (err) {
+        console.error('failed to fetch id column', err);
+      }
+    }
+    return columnName || null;
+  }
+
+  get defaultLabel(): string | null {
+    return this.get('default_label') || null;
+  }
+
+  initialize(attributes: any, options: any) {
+    super.initialize(attributes, options);
+    this.on('change:column_name', this.onColumnNameChange, this);
+  }
+
+  onColumnNameChange(change?: any) {
+    this._updateRequested.emit(void 0);
+  }
+
+  async registerGraph(hasGraph: IHasGraph): Promise<void> {
+    this._graph = hasGraph;
+    await hasGraph.rendered;
+  }
+
+  async onUpdate(hasGraph: IHasGraph): Promise<void> {
+    if (hasGraph !== this._graph) {
+      await this.registerGraph(hasGraph);
+    }
+
+    const { columnName, defaultLabel } = this;
+
+    hasGraph.graph.nodeLabel((node: NodeObject) => {
+      let label = null;
+      if (columnName != null) {
+        label = node[columnName];
+      }
+      return label == null ? defaultLabel : label;
+    });
+  }
+}
diff --git a/js/widgets/behaviors/selection.ts b/js/widgets/behaviors/selection.ts
new file mode 100644
index 00000000..ca6568c1
--- /dev/null
+++ b/js/widgets/behaviors/selection.ts
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import type { NodeObject } from 'force-graph';
+
+import { WidgetModel, unpack_models as deserialize } from '@jupyter-widgets/base';
+
+import { DEFAULT_COLORS, IHasGraph, WIDGET_DEFAULTS } from '../../tokens';
+
+import { BehaviorModel } from './base';
+
+export type TSelectedSet = Set<string | number>;
+
+export class NodeSelectionModel extends BehaviorModel {
+  static model_name = 'NodeSelectionModel';
+  static serializers = {
+    ...WidgetModel.serializers,
+    value: { deserialize },
+  };
+
+  protected _graph: IHasGraph | null = null;
+
+  defaults() {
+    return {
+      ...super.defaults(),
+      ...WIDGET_DEFAULTS,
+      _model_name: NodeSelectionModel.model_name,
+      selected: [],
+      selected_color: DEFAULT_COLORS.selected,
+      not_selected_color: DEFAULT_COLORS.notSelected,
+      multiple: true,
+    };
+  }
+
+  initialize(attributes: any, options: any) {
+    super.initialize(attributes, options);
+    this.on('change:selected', this.onValueChange, this);
+    this.onValueChange();
+  }
+
+  onValueChange(change?: any) {
+    this._updateRequested.emit(void 0);
+  }
+
+  get selected(): TSelectedSet {
+    return new Set([...(this.get('selected') || [])]);
+  }
+
+  set selected(selected: TSelectedSet) {
+    this.set({ selected: [...selected] });
+    this.save_changes();
+  }
+
+  get selectedColor(): string {
+    return this.get('selected_color') || DEFAULT_COLORS.selected;
+  }
+
+  get notSelectedColor(): string {
+    return this.get('not_selected_color') || DEFAULT_COLORS.notSelected;
+  }
+
+  async registerGraph(hasGraph: IHasGraph): Promise<void> {
+    this._graph = hasGraph;
+    await hasGraph.rendered;
+    hasGraph.graph.onNodeClick(this.onNodeClick);
+  }
+
+  onNodeClick = (node: NodeObject, event: MouseEvent): void => {
+    let { selected } = this;
+    const id = node.id;
+    if (this.get('multiple') && (event.ctrlKey || event.shiftKey || event.altKey)) {
+      selected.has(id) ? selected.delete(id) : selected.add(id);
+    } else {
+      selected.clear();
+      selected.add(id);
+    }
+
+    this.selected = selected;
+  };
+
+  async onUpdate(hasGraph: IHasGraph): Promise<void> {
+    if (hasGraph !== this._graph) {
+      await this.registerGraph(hasGraph);
+    }
+
+    const { selected, selectedColor, notSelectedColor } = this;
+
+    hasGraph.graph.nodeColor((node: NodeObject) => {
+      return selected.has(node.id) ? selectedColor : notSelectedColor;
+    });
+  }
+}
diff --git a/js/widgets/display.ts b/js/widgets/display/2d.ts
similarity index 54%
rename from js/widgets/display.ts
rename to js/widgets/display/2d.ts
index ef0f4253..23c5c6f2 100644
--- a/js/widgets/display.ts
+++ b/js/widgets/display/2d.ts
@@ -1,9 +1,7 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-import ForceGraph3D from '3d-force-graph';
-import { ForceGraph3DInstance } from '3d-force-graph';
 import ForceGraph from 'force-graph';
 import { ForceGraphInstance, GraphData } from 'force-graph';
 
@@ -23,7 +21,7 @@ import {
   IHasGraph,
   ISource,
   WIDGET_DEFAULTS,
-} from '../tokens';
+} from '../../tokens';
 
 export class ForceGraphModel extends DOMWidgetModel {
   static model_name = 'ForceGraphModel';
@@ -50,9 +48,12 @@ export class ForceGraphModel extends DOMWidgetModel {
   }
 }
 
-export class ForceGraphView extends DOMWidgetView implements IHasGraph {
+export class ForceGraphView<T = ForceGraphInstance>
+  extends DOMWidgetView
+  implements IHasGraph<T>
+{
   static view_name = 'ForceGraphView';
-  graph: ForceGraphInstance;
+  graph: T;
   model: ForceGraphModel;
 
   protected _rendered: PromiseDelegate<void>;
@@ -61,6 +62,10 @@ export class ForceGraphView extends DOMWidgetView implements IHasGraph {
     return this.model.get('source');
   }
 
+  get rendered(): Promise<void> {
+    return this._rendered.promise;
+  }
+
   initialize(parameters: any) {
     super.initialize(parameters);
     this._rendered = new PromiseDelegate();
@@ -73,99 +78,43 @@ export class ForceGraphView extends DOMWidgetView implements IHasGraph {
   async render(): Promise<void> {
     const root = this.el as HTMLDivElement;
     const containerDiv = document.createElement('div');
+    containerDiv.setAttribute('data-jp-suppress-context-menu', 'true');
     root.appendChild(containerDiv);
-    this.graph = ForceGraph()(containerDiv);
+    this.graph = this.createGraph(containerDiv);
     this._rendered.resolve(void 0);
     await this.update();
   }
 
+  protected createGraph(containerDiv: HTMLDivElement): T {
+    return ForceGraph()(containerDiv) as any;
+  }
+
   async update(): Promise<void> {
     await this._rendered.promise;
     let { graphData } = this.model;
     DEBUG && console.warn(`${EMOJI} updating...`, graphData);
-    this.graph.graphData(graphData);
+    (this.graph as any).graphData(graphData);
     await this.postUpdate();
   }
 
   async postUpdate(): Promise<void> {
     const behaviors: IBehave[] = this.model.get('behaviors') || [];
+    const promises: Promise<any>[] = [];
     for (const behavior of behaviors) {
-      behavior.onUpdate(this);
+      promises.push(behavior.onUpdate(this));
     }
+    await Promise.all(promises);
   }
 
-  onBehaviorsChange() {
+  async onBehaviorsChange(): Promise<void> {
+    // TODO: disconnect old model...
     const behaviors: IBehave[] = this.model.get('behaviors') || [];
+    const promises: Promise<any>[] = [];
     for (const behavior of behaviors) {
       behavior.updateRequested.connect(this.postUpdate, this);
+      promises.push(behavior.onUpdate(this));
     }
-  }
-
-  onSourceChange(change?: any) {
-    // TODO disconnect old model...
-    let source = this.model.get('source');
-    if (source) {
-      source.dataUpdated.connect(this.update, this);
-      this.update();
-    }
-  }
-}
-
-export class ForceGraph3DModel extends DOMWidgetModel {
-  static model_name = 'ForceGraph3DModel';
-  static serializers = {
-    ...DOMWidgetModel.serializers,
-    source: { deserialize },
-  };
-
-  defaults() {
-    return {
-      ...super.defaults(),
-      ...WIDGET_DEFAULTS,
-      _model_name: ForceGraph3DModel.model_name,
-      _view_name: ForceGraph3DView.view_name,
-      source: null,
-    };
-  }
-
-  get graphData(): GraphData {
-    const source = this.get('source');
-    return source ? source.graphData : EMPTY_GRAPH_DATA;
-  }
-}
-
-export class ForceGraph3DView extends DOMWidgetView {
-  static view_name = 'ForceGraph3DView';
-  graph: ForceGraph3DInstance;
-  model: ForceGraph3DModel;
-
-  protected _rendered: PromiseDelegate<void>;
-
-  get source(): ISource {
-    return this.model.get('source');
-  }
-
-  initialize(parameters: any) {
-    super.initialize(parameters);
-    this._rendered = new PromiseDelegate();
-    this.model.on('change:source', this.onSourceChange, this);
-    this.onSourceChange();
-  }
-
-  async render(): Promise<void> {
-    const root = this.el as HTMLDivElement;
-    const containerDiv = document.createElement('div');
-    root.appendChild(containerDiv);
-    this.graph = ForceGraph3D()(containerDiv);
-    this._rendered.resolve(void 0);
-    await this.update();
-  }
-
-  async update(): Promise<void> {
-    await this._rendered.promise;
-    let { graphData } = this.model;
-    DEBUG && console.warn(`${EMOJI} updating...`, graphData);
-    this.graph.graphData(graphData);
+    await Promise.all(promises);
   }
 
   onSourceChange(change?: any) {
diff --git a/js/widgets/display/3d.ts b/js/widgets/display/3d.ts
new file mode 100644
index 00000000..ef6bde5d
--- /dev/null
+++ b/js/widgets/display/3d.ts
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import ForceGraph3D, { ForceGraph3DInstance } from '3d-force-graph';
+
+import { ForceGraphModel, ForceGraphView } from './2d';
+
+export class ForceGraph3DModel extends ForceGraphModel {
+  static model_name = 'ForceGraph3DModel';
+  static serializers = {
+    ...ForceGraphModel.serializers,
+  };
+
+  defaults() {
+    return {
+      ...super.defaults(),
+      _model_name: ForceGraph3DModel.model_name,
+      _view_name: ForceGraph3DView.view_name,
+    };
+  }
+}
+
+export class ForceGraph3DView extends ForceGraphView<ForceGraph3DInstance> {
+  static view_name = 'ForceGraph3DView';
+  model: ForceGraph3DModel;
+
+  protected createGraph(containerDiv: HTMLDivElement): ForceGraph3DInstance {
+    return ForceGraph3D()(containerDiv);
+  }
+}
diff --git a/js/widgets/display/index.ts b/js/widgets/display/index.ts
new file mode 100644
index 00000000..f380157f
--- /dev/null
+++ b/js/widgets/display/index.ts
@@ -0,0 +1,6 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+export * from './2d';
+export * from './3d';
diff --git a/js/widgets/index.ts b/js/widgets/index.ts
index d90d158a..a1bf8ddd 100644
--- a/js/widgets/index.ts
+++ b/js/widgets/index.ts
@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-export * from './behavior';
+export * from './behaviors';
 export * from './display';
-export * from './source';
+export * from './sources';
diff --git a/js/widgets/serializers.ts b/js/widgets/serializers.ts
new file mode 100644
index 00000000..83c14180
--- /dev/null
+++ b/js/widgets/serializers.ts
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import { compress, decompress, init } from '@bokuweb/zstd-wasm';
+import { Buffer } from 'buffer';
+
+import { IWidgetManager, WidgetModel } from '@jupyter-widgets/base';
+
+import { DEBUG, EMOJI } from '../tokens';
+
+export interface IReceivedSerializedDataFrame {
+  buffer: DataView;
+}
+
+export interface ISendSerializedDataFrame {
+  buffer: DataView;
+}
+
+export function jsonToDataFrame(
+  obj: IReceivedSerializedDataFrame | null,
+  manager?: IWidgetManager
+): any {
+  const data = decompress(Buffer.from(obj.buffer.buffer));
+  const json = JSON.parse(Buffer.prototype.toString.call(data, 'utf8'));
+  return json;
+}
+
+export function dataFrameToJson(
+  obj: any,
+  widget?: WidgetModel
+): ISendSerializedDataFrame | null {
+  console.warn(compress);
+  if (obj === null) {
+    return null;
+  }
+  return {
+    buffer: null as any,
+  };
+}
+
+export const dataframe_serialization = {
+  deserialize: jsonToDataFrame,
+  serialize: dataFrameToJson,
+};
+
+export async function initializeZstd() {
+  await init();
+  DEBUG && console.warn(`${EMOJI} zstd loaded`);
+}
diff --git a/js/widgets/source.ts b/js/widgets/source.ts
deleted file mode 100644
index 9c7d3d58..00000000
--- a/js/widgets/source.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2022 ipyforcegraph contributors.
- * Distributed under the terms of the Modified BSD License.
- */
-import { GraphData } from 'force-graph';
-import type ndarray from 'ndarray';
-
-import { ISignal, Signal } from '@lumino/signaling';
-
-import { WidgetModel, unpack_models as deserialize } from '@jupyter-widgets/base';
-
-import { DEBUG, EMOJI, WIDGET_DEFAULTS } from '../tokens';
-
-/**
- * A model which wraps a number of `ndarray.NdArray` to describe a graph.
- */
-export class SourceModel extends WidgetModel {
-  static model_name = 'SourceModel';
-  static serializers = {
-    ...WidgetModel.serializers,
-    nodes: { deserialize },
-    links: { deserialize },
-    metadata: { deserialize },
-  };
-
-  protected _dataUpdated: Signal<SourceModel, void>;
-
-  defaults() {
-    return {
-      ...super.defaults(),
-      ...WIDGET_DEFAULTS,
-      _model_name: SourceModel.model_name,
-      nodes: null,
-      links: null,
-      metadata: null,
-    };
-  }
-
-  initialize(attributes: any, options: any) {
-    super.initialize(attributes, options);
-    this._dataUpdated = new Signal(this);
-
-    this.on('change:nodes', this.onNodesChange, this);
-    this.on('change:links', this.onLinksChange, this);
-    this.on('change:metadata', this.onMetadataChange, this);
-
-    this.onNodesChange();
-    this.onLinksChange();
-    this.onMetadataChange();
-    this.graphUpdate();
-  }
-
-  get dataUpdated(): ISignal<SourceModel, void> {
-    return this._dataUpdated;
-  }
-
-  get graphData(): GraphData {
-    const nodes: ndarray.NdArray = this.get('nodes')?.get('array');
-    const links: ndarray.NdArray = this.get('links')?.get('array');
-    const graph: GraphData = {
-      nodes: [],
-      links: [],
-    };
-
-    if (nodes && nodes.shape[0]) {
-      for (let i = 0; i < nodes.shape[0]; ++i) {
-        graph.nodes[i] = { id: i };
-      }
-    }
-
-    if (links && links.shape[0]) {
-      for (let i = 0; i < links.shape[0]; ++i) {
-        graph.links.push({ source: links.get(i, 0), target: links.get(i, 1) });
-      }
-    }
-
-    DEBUG && console.warn(`${EMOJI} updating...`, graph);
-
-    return graph;
-  }
-
-  onNodesChange(change?: any) {
-    let nodes = this.get('nodes');
-    if (nodes) {
-      nodes.on('change:array', this.graphUpdate, this);
-    }
-  }
-
-  onLinksChange(change?: any) {
-    let links = this.get('links');
-    if (links) {
-      links.on('change:array', this.graphUpdate, this);
-    }
-  }
-
-  onMetadataChange(change?: any) {
-    let metadata = this.get('metadata');
-    if (metadata) {
-      metadata.on('change:array', this.graphUpdate, this);
-    }
-  }
-
-  graphUpdate(change?: any) {
-    //TODO throttle / debounce emitting events
-    this._dataUpdated.emit(void 0);
-  }
-}
diff --git a/js/widgets/sources/dataframe.ts b/js/widgets/sources/dataframe.ts
new file mode 100644
index 00000000..574860b2
--- /dev/null
+++ b/js/widgets/sources/dataframe.ts
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import { GraphData } from 'force-graph';
+
+import { ISignal, Signal } from '@lumino/signaling';
+
+import { WidgetModel } from '@jupyter-widgets/base';
+
+import { DEFAULT_COLUMNS, WIDGET_DEFAULTS } from '../../tokens';
+import { jsonToDataFrame } from '../serializers';
+
+const emptyArray = Object.freeze([]);
+
+export class DataFrameSourceModel extends WidgetModel {
+  static model_name = 'DataFrameSourceModel';
+  static serializers = {
+    ...WidgetModel.serializers,
+    nodes: { deserialize: jsonToDataFrame },
+    links: { deserialize: jsonToDataFrame },
+  };
+
+  protected _dataUpdated: Signal<DataFrameSourceModel, void>;
+
+  defaults() {
+    return {
+      ...super.defaults(),
+      ...WIDGET_DEFAULTS,
+      _model_name: DataFrameSourceModel.model_name,
+      nodes: null,
+      links: null,
+      node_id_column: DEFAULT_COLUMNS.id,
+      link_source_column: DEFAULT_COLUMNS.source,
+      link_target_column: DEFAULT_COLUMNS.target,
+    };
+  }
+
+  initialize(attributes: any, options: any) {
+    super.initialize(attributes, options);
+    this._dataUpdated = new Signal(this);
+
+    this.on('change:nodes', this.graphUpdate, this);
+    this.on('change:links', this.graphUpdate, this);
+
+    this.graphUpdate();
+  }
+
+  get dataUpdated(): ISignal<DataFrameSourceModel, void> {
+    return this._dataUpdated;
+  }
+
+  get nodeIdColumn() {
+    return this.get('node_id_column') || DEFAULT_COLUMNS.id;
+  }
+
+  get linkSourceColumn() {
+    return this.get('link_source_column') || DEFAULT_COLUMNS.source;
+  }
+
+  get linkTargetColumn() {
+    return this.get('link_target_column') || DEFAULT_COLUMNS.target;
+  }
+
+  get nodes() {
+    return this.get('nodes') || emptyArray;
+  }
+
+  get links() {
+    return this.get('links') || emptyArray;
+  }
+
+  get graphData(): GraphData {
+    const graph: GraphData = {
+      nodes: [],
+      links: [],
+    };
+
+    const { nodes, links, nodeIdColumn, linkSourceColumn, linkTargetColumn } = this;
+
+    const nodeColumns = Object.keys(nodes);
+
+    const nodeCount = (nodes[nodeIdColumn] || emptyArray).length;
+    const linkCount = (links[linkSourceColumn] || emptyArray).length;
+
+    const hasIdColumn = nodes[nodeIdColumn] != null;
+
+    for (let idx = 0; idx < nodeCount; idx++) {
+      let node = { id: hasIdColumn ? nodes[nodeIdColumn][idx] : idx };
+      for (const col of nodeColumns) {
+        node[col] = nodes[col][idx];
+      }
+      graph.nodes.push(node);
+    }
+
+    for (let idx = 0; idx < linkCount; idx++) {
+      graph.links.push({
+        source: links[linkSourceColumn][idx],
+        target: links[linkTargetColumn][idx],
+      });
+    }
+
+    return graph;
+  }
+
+  graphUpdate(change?: any) {
+    //TODO throttle / debounce emitting events
+    this._dataUpdated.emit(void 0);
+  }
+}
diff --git a/js/widgets/sources/index.ts b/js/widgets/sources/index.ts
new file mode 100644
index 00000000..e6b681de
--- /dev/null
+++ b/js/widgets/sources/index.ts
@@ -0,0 +1,5 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+export * from './dataframe';
diff --git a/lite/jupyter_lite_config.json b/lite/jupyter_lite_config.json
index 6d791236..c6dd3a68 100644
--- a/lite/jupyter_lite_config.json
+++ b/lite/jupyter_lite_config.json
@@ -1,7 +1,9 @@
 {
   "LiteBuildConfig": {
-    "piplite_urls": ["../dist"],
     "output_dir": "../build/lite",
     "contents": ["../examples"]
+  },
+  "PipliteAddon": {
+    "piplite_urls": ["../dist"]
   }
 }
diff --git a/package.json b/package.json
index 53204b7b..571e2006 100644
--- a/package.json
+++ b/package.json
@@ -41,13 +41,16 @@
   "resolutions": {
     "verdaccio": "file:./scripts/not-a-package",
     "typescript": "~4.9.3",
+    "json5": "^2.1.1",
     "prettier": "^2.8.0"
   },
   "dependencies": {
+    "@bokuweb/zstd-wasm": "^0.0.17",
     "@jupyter-widgets/base": "^6.0.1",
     "@jupyter-widgets/controls": "^5.0.1",
     "@jupyter-widgets/jupyterlab-manager": "^5.0.0",
     "3d-force-graph": "~1.70.17",
+    "buffer": "^6.0.3",
     "force-graph": "~1.42.16",
     "jupyter-datawidgets": "^5.5.2"
   },
@@ -58,7 +61,6 @@
     "@jupyterlab/theme-light-extension": "3",
     "@trivago/prettier-plugin-sort-imports": "^4.0.0",
     "@types/lodash": "^4.14.162",
-    "@types/ndarray": "^1.0.11",
     "npm-run-all": "^4.1.5",
     "prettier": "^2.8.0",
     "prettier-package-json": "^2.7.0",
@@ -94,6 +96,9 @@
       },
       "jupyter-datawidgets": {
         "bundled": true
+      },
+      "@bokuweb/zstd-wasm": {
+        "bundled": true
       }
     }
   },
diff --git a/pyproject.toml b/pyproject.toml
index aefe2489..aed2053f 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -28,9 +28,11 @@ classifiers = [
 ]
 requires-python = ">=3.8"
 dependencies = [
-    "ipydatawidgets",
     "ipywidgets >=8.0.4,<9",
     "networkx",
+    "numcodecs",
+    "traittypes",
+    "pandas",
 ]
 
 [project.urls]
diff --git a/scripts/__init__.py b/scripts/__init__.py
index de09291b..1be58b25 100644
--- a/scripts/__init__.py
+++ b/scripts/__init__.py
@@ -1,2 +1,2 @@
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
diff --git a/scripts/lab.py b/scripts/lab.py
index aaea3b6b..8efe4019 100644
--- a/scripts/lab.py
+++ b/scripts/lab.py
@@ -1,7 +1,7 @@
 """ handle lingering issues with jupyterlab 1.x build
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import shutil
diff --git a/scripts/nblint.py b/scripts/nblint.py
index 0d85330a..eebfb17e 100644
--- a/scripts/nblint.py
+++ b/scripts/nblint.py
@@ -1,7 +1,7 @@
 """ linter and formatter of notebooks
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import shutil
diff --git a/scripts/preflight.py b/scripts/preflight.py
index dcde3dae..7d3e6498 100644
--- a/scripts/preflight.py
+++ b/scripts/preflight.py
@@ -3,7 +3,7 @@
     be careful about imports here:
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import json
diff --git a/scripts/project.py b/scripts/project.py
index 53ac8870..a28bb6d6 100644
--- a/scripts/project.py
+++ b/scripts/project.py
@@ -3,7 +3,7 @@
     this should not import anything not in py36+ stdlib, or any local paths
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import itertools
@@ -158,7 +158,7 @@ def _get_boolish(name, default="false"):
 DOCS_BUILD = BUILD / "docs"
 DOCS_CONF = DOCS / "conf.py"
 DICTIONARY = DOCS / "dictionary.txt"
-LITE_SPEC = ["--pre", "jupyterlite==0.1.0b16"]
+LITE_SPEC = ["--pre", "jupyterlite==0.1.0b17"]
 LITE_BUILD = BUILD / "lite"
 LITE_SHA256SUMS = LITE_BUILD / "SHA256SUMS"
 
@@ -178,7 +178,9 @@ def _get_boolish(name, default="false"):
 # tests
 EXAMPLES = ROOT / "examples"
 EXAMPLE_IPYNB = [
-    p for p in EXAMPLES.rglob("*.ipynb") if ".ipynb_checkpoints" not in str(p)
+    p
+    for p in EXAMPLES.glob("*.ipynb")  # only look in the root for top-level examples
+    if ".ipynb_checkpoints" not in str(p) and "untitled" not in str(p).lower()
 ]
 EXAMPLE_JSON = [
     p for p in EXAMPLES.rglob("*.json") if ".ipynb_checkpoints" not in str(p)
@@ -228,7 +230,7 @@ def _get_boolish(name, default="false"):
 
 HTMLCOV = BUILD / "htmlcov"
 HTMLCOV_INDEX = HTMLCOV / "index.html"
-PYTEST_COV_THRESHOLD = 17
+PYTEST_COV_THRESHOLD = 13
 PYTEST_HTML = BUILD / "pytest.html"
 PYTEST_XUNIT = BUILD / "pytest.xunit.xml"
 
diff --git a/scripts/reporter.py b/scripts/reporter.py
index 3bbecd00..87633d1f 100644
--- a/scripts/reporter.py
+++ b/scripts/reporter.py
@@ -2,7 +2,7 @@
 
 # Copyright (c) 2020 Robots from Jupyter
 # Distributed under the terms of the Modified BSD License.
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 
diff --git a/scripts/utils.py b/scripts/utils.py
index e1ec63b9..fd55343b 100644
--- a/scripts/utils.py
+++ b/scripts/utils.py
@@ -2,7 +2,7 @@
 
 # Copyright (c) 2020 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import re
diff --git a/src/ipyforcegraph/__init__.py b/src/ipyforcegraph/__init__.py
index 2b48a02e..ca6c9cd6 100644
--- a/src/ipyforcegraph/__init__.py
+++ b/src/ipyforcegraph/__init__.py
@@ -1,5 +1,5 @@
 """Main entrypoint for ipyforcegraph."""
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 from .constants import EXTENSION_NAME, __version__
diff --git a/src/ipyforcegraph/_base.py b/src/ipyforcegraph/_base.py
index 351253af..245da2fd 100644
--- a/src/ipyforcegraph/_base.py
+++ b/src/ipyforcegraph/_base.py
@@ -1,5 +1,5 @@
 """Base widget identification for ipyforcegraph."""
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import ipywidgets as W
diff --git a/src/ipyforcegraph/behaviors.py b/src/ipyforcegraph/behaviors.py
index b3a3ef74..d0bda951 100644
--- a/src/ipyforcegraph/behaviors.py
+++ b/src/ipyforcegraph/behaviors.py
@@ -1,25 +1,55 @@
 """Behaviors for ipyforcegraph."""
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
+import typing
+
 import ipywidgets as W
-import numpy as np
 import traitlets as T
-from ipydatawidgets import NDArrayWidget
 
 from ._base import Behavior
 
 
 @W.register
 class NodeSelection(Behavior):
+    """Enable node selection with synced ids of selected nodes."""
+
     _model_name: str = T.Unicode("NodeSelectionModel").tag(sync=True)
 
-    value: NDArrayWidget = T.Instance(NDArrayWidget).tag(
-        sync=True, **W.widget_serialization
-    )
+    selected: typing.Tuple[int] = W.TypedTuple(
+        T.Union((T.Int(), T.Unicode())),
+        allow_none=True,
+        help="the ids of any selected nodes",
+    ).tag(sync=True)
+
     multiple: bool = T.Bool(True).tag(sync=True)
 
-    @T.default("value")
-    def _default_value(self):
-        return NDArrayWidget(np.zeros(0), dtype="int")
+    selected_color: str = T.Unicode("#B3A369", help="the color of selected nodes").tag(
+        sync=True
+    )
+
+    not_selected_color: str = T.Unicode(
+        "#003057", help="the color of unselected nodes"
+    ).tag(sync=True)
+
+
+@W.register
+class NodeLabels(Behavior):
+    """Display node labels."""
+
+    _model_name: str = T.Unicode("NodeLabelModel").tag(sync=True)
+
+    column_name: str = T.Unicode(
+        None,
+        allow_none=True,
+        help=(
+            "name of the source column to use for node labels. If ``None``, use "
+            "the source's ``node_id_column``."
+        ),
+    ).tag(sync=True)
+
+    default_label: str = T.Unicode(
+        allow_none=True,
+        help=("a fallback label if ``column_name`` doesn't exist or is empty"),
+    ).tag(sync=True)
diff --git a/src/ipyforcegraph/constants.py b/src/ipyforcegraph/constants.py
index 8c58c767..51133cf9 100644
--- a/src/ipyforcegraph/constants.py
+++ b/src/ipyforcegraph/constants.py
@@ -1,6 +1,6 @@
 """Constants for ipyforcegraph."""
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 try:
diff --git a/src/ipyforcegraph/forcegraph.py b/src/ipyforcegraph/forcegraph.py
index 82157264..36c16788 100644
--- a/src/ipyforcegraph/forcegraph.py
+++ b/src/ipyforcegraph/forcegraph.py
@@ -1,41 +1,13 @@
 """Force-directed graph widgets."""
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import ipywidgets as W
-import numpy as np
 import traitlets as T
-from ipydatawidgets import NDArrayWidget
 
 from ._base import Behavior, ForceBase
-
-
-@W.register
-class Source(ForceBase):
-    _model_name = T.Unicode("SourceModel").tag(sync=True)
-
-    nodes: NDArrayWidget = T.Instance(NDArrayWidget).tag(
-        sync=True, **W.widget_serialization
-    )
-    links: NDArrayWidget = T.Instance(NDArrayWidget).tag(
-        sync=True, **W.widget_serialization
-    )
-    metadata: NDArrayWidget = T.Instance(NDArrayWidget).tag(
-        sync=True, **W.widget_serialization
-    )
-
-    @T.default("nodes")
-    def _default_nodes(self):
-        return NDArrayWidget(np.zeros(0), dtype="int")
-
-    @T.default("links")
-    def _default_links(self):
-        return NDArrayWidget(np.zeros(0), dtype="int")
-
-    @T.default("metadata")
-    def _default_metadata(self):
-        return NDArrayWidget(np.zeros(0), dtype="int")
+from .sources.dataframe import DataFrameSource
 
 
 @W.register
@@ -45,17 +17,17 @@ class ForceGraph(W.DOMWidget, ForceBase):
     _model_name: str = T.Unicode("ForceGraphModel").tag(sync=True)
     _view_name: str = T.Unicode("ForceGraphView").tag(sync=True)
 
-    source: Source = T.Instance(Source, kw={}).tag(sync=True, **W.widget_serialization)
-    behaviors: list[Behavior] = W.TypedTuple(T.Instance(Behavior), kw={}).tag(
+    source: DataFrameSource = T.Instance(DataFrameSource, kw={}).tag(
+        sync=True, **W.widget_serialization
+    )
+    behaviors: tuple[Behavior] = W.TypedTuple(T.Instance(Behavior), kw={}).tag(
         sync=True, **W.widget_serialization
     )
 
 
 @W.register
-class ForceGraph3D(W.DOMWidget, ForceBase):
+class ForceGraph3D(ForceGraph):
     """3D force-directed graph widget."""
 
     _model_name: str = T.Unicode("ForceGraph3DModel").tag(sync=True)
     _view_name: str = T.Unicode("ForceGraph3DView").tag(sync=True)
-
-    source: Source = T.Instance(Source, kw={}).tag(sync=True, **W.widget_serialization)
diff --git a/src/ipyforcegraph/js.py b/src/ipyforcegraph/js.py
index 011ac227..f7fe9989 100644
--- a/src/ipyforcegraph/js.py
+++ b/src/ipyforcegraph/js.py
@@ -1,6 +1,6 @@
 """Client resource discovery and metadata for ipyforcegraph."""
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import sys
diff --git a/src/ipyforcegraph/serializers.py b/src/ipyforcegraph/serializers.py
new file mode 100644
index 00000000..c458e24b
--- /dev/null
+++ b/src/ipyforcegraph/serializers.py
@@ -0,0 +1,52 @@
+# Copyright (c) 2023 ipyforcegraph contributors.
+# Distributed under the terms of the Modified BSD License.
+
+import json
+
+import ipywidgets as W
+import numcodecs as N
+import pandas as P
+import traitlets as T
+
+HAS_ORJSON = False
+try:
+    import orjson
+
+    HAS_ORJSON = True
+except ImportError:
+    pass
+
+
+def dataframe_to_json(value: P.DataFrame, widget: W.Widget):
+    """DataFrame JSON serializer."""
+    if value is None:
+        return None
+    if value is T.Undefined:
+        raise T.TraitError("Cannot serialize undefined dataframe!")
+
+    df_data = value.to_dict(orient="list")
+
+    if HAS_ORJSON:
+        df_json = orjson.dumps(df_data)
+    else:
+        df_json = json.dumps(df_data).encode("utf-8")
+
+    return {"buffer": memoryview(N.zstd.compress(df_json))}
+
+
+def dataframe_from_json(value: P.DataFrame, widget: W.Widget):
+    """DataFrame JSON de-serializer."""
+    if value is None:
+        return None
+
+    if HAS_ORJSON:
+        df_data = orjson.loads(value)
+    else:
+        df_data = json.loads(df_data)
+
+    df_json = json.loads(N.zstd.decompress(value["buffer"]))
+
+    return P.DataFrame(df_json)
+
+
+dataframe_serialization = dict(to_json=dataframe_to_json, from_json=dataframe_from_json)
diff --git a/src/ipyforcegraph/sources/__init__.py b/src/ipyforcegraph/sources/__init__.py
new file mode 100644
index 00000000..1be58b25
--- /dev/null
+++ b/src/ipyforcegraph/sources/__init__.py
@@ -0,0 +1,2 @@
+# Copyright (c) 2023 ipyforcegraph contributors.
+# Distributed under the terms of the Modified BSD License.
diff --git a/src/ipyforcegraph/sources/dataframe.py b/src/ipyforcegraph/sources/dataframe.py
new file mode 100644
index 00000000..26d4e83f
--- /dev/null
+++ b/src/ipyforcegraph/sources/dataframe.py
@@ -0,0 +1,59 @@
+# Copyright (c) 2023 ipyforcegraph contributors.
+# Distributed under the terms of the Modified BSD License.
+
+import ipywidgets as W
+import pandas as P
+import traitlets as T
+import traittypes as TT
+
+from .._base import ForceBase
+from ..serializers import dataframe_serialization
+
+
+@W.register
+class DataFrameSource(ForceBase):
+    """A Graph Source that stores the nodes and links as a pandas DataFrame."""
+
+    _model_name: str = T.Unicode("DataFrameSourceModel").tag(sync=True)
+
+    nodes: P.DataFrame = TT.PandasType(
+        klass=P.DataFrame, help="the DataFrame of node metadata"
+    ).tag(sync=True, **dataframe_serialization)
+
+    node_id_column: str = T.Unicode(
+        "id",
+        help="the name of the column for a node's identifier, or 0-based position in the column if None",
+    ).tag(sync=True)
+
+    links: P.DataFrame = TT.PandasType(
+        klass=P.DataFrame, help="the DataFrame of link metadata"
+    ).tag(sync=True, **dataframe_serialization)
+
+    link_source_column: str = T.Unicode(
+        "source",
+        help="the name of the column for a link's source, defaulting to ``source``",
+    ).tag(sync=True)
+
+    link_target_column: str = T.Unicode(
+        "target",
+        help="the name of the column for a link's target, defaulting to ``target``",
+    ).tag(sync=True)
+
+    # TODO: these go on a subclass of PandasType
+    # sync_node_columns: tuple[str] = W.TypedTuple(
+    #     klass=T.Unicode(),
+    #     allow_none=True,
+    #     help="The columns to provide to the frontend for nodes: send all if ``None``"
+    # ).tag(sync=True)
+    # sync_link_columns: tuple[str] = W.TypedTuple(
+    #     klass=T.Unicode(),
+    #     allow_none=True,
+    #     help="The columns to provide to the frontend for links: send all if ``None``"
+    # ).tag(sync=True)
+
+    def __repr__(self):
+        """A dumb repr to avoid string nasty pandas comparison stuff."""
+        name = self.__class__.__name__
+        nodes_shape = self.nodes.shape if self.nodes is not None else None
+        links_shape = self.links.shape if self.links is not None else None
+        return f"{name}(nodes={nodes_shape}, links={links_shape})"
diff --git a/style/index.css b/style/index.css
index 7eae5dd9..8b92635c 100644
--- a/style/index.css
+++ b/style/index.css
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2022 ipyforcegraph contributors.
+ * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
 */
diff --git a/webpack.config.js b/webpack.config.js
index 772e2031..e02f34bb 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -3,12 +3,21 @@ module.exports = {
     clean: true,
   },
   devtool: 'source-map',
+  resolve: {
+    fallback: {
+      buffer: require.resolve('buffer/'),
+    },
+  },
   module: {
     rules: [
       {
         test: /\.js$/,
         use: ['source-map-loader'],
       },
+      {
+        test: /zstd\.wasm/,
+        type: 'asset/resource',
+      },
     ],
   },
 };
diff --git a/yarn.lock b/yarn.lock
index dc22118f..dfbdb036 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -285,6 +285,11 @@
     classnames "^2.2"
     tslib "~2.3.1"
 
+"@bokuweb/zstd-wasm@^0.0.17":
+  version "0.0.17"
+  resolved "https://registry.npmjs.org/@bokuweb/zstd-wasm/-/zstd-wasm-0.0.17.tgz#e180d65fa89d498b2b62cfd272a662c58422e2a4"
+  integrity sha512-Ov4HQePHwgeVMRh5ub9+Rk2+SuzvAgeq7epWxEtzQ8WnzVyh3bZQQsdz32rKpd3HU3M+iRPip2/naIyDPjPZUQ==
+
 "@discoveryjs/json-ext@^0.5.0":
   version "0.5.7"
   resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
@@ -1258,15 +1263,10 @@
   resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
   integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
 
-"@types/ndarray@^1.0.11":
-  version "1.0.11"
-  resolved "https://registry.npmjs.org/@types/ndarray/-/ndarray-1.0.11.tgz#a78730ac1fd10ea01cda6954dba7b3bf4fa126f4"
-  integrity sha512-hOZVTN24zDHwCHaW7mF9n1vHJt83fZhNZ0YYRBwQGhA96yBWWDPTDDlqJatagHIOJB0a4xoNkNc+t/Cxd+6qUA==
-
 "@types/node@*":
-  version "18.11.17"
-  resolved "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz#5c009e1d9c38f4a2a9d45c0b0c493fe6cdb4bcb5"
-  integrity sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==
+  version "18.7.23"
+  resolved "https://registry.npmjs.org/@types/node/-/node-18.7.23.tgz#75c580983846181ebe5f4abc40fe9dfb2d65665f"
+  integrity sha512-DWNcCHolDq0ZKGizjx2DZjR/PqsYwAcYUJmfMWqtVU2MBMG5Mo+xFZrhGId5r/O5HOuMPyQEcM6KUBp5lBZZBg==
 
 "@types/parse-author@^2.0.0":
   version "2.0.1"
@@ -1651,6 +1651,14 @@ buffer@^5.5.0, buffer@^5.6.0:
     base64-js "^1.3.1"
     ieee754 "^1.1.13"
 
+buffer@^6.0.3:
+  version "6.0.3"
+  resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
+  integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
+  dependencies:
+    base64-js "^1.3.1"
+    ieee754 "^1.2.1"
+
 cacache@^15.0.5:
   version "15.3.0"
   resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb"
@@ -2754,7 +2762,7 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
   resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
   integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
 
-ieee754@^1.1.13:
+ieee754@^1.1.13, ieee754@^1.2.1:
   version "1.2.1"
   resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
   integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
@@ -3094,14 +3102,7 @@ json-schema-traverse@^0.4.1:
   resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
   integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
 
-json5@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
-  integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
-  dependencies:
-    minimist "^1.2.0"
-
-json5@^2.1.1, json5@^2.1.2, json5@^2.2.1:
+json5@^1.0.1, json5@^2.1.1, json5@^2.1.2, json5@^2.2.1:
   version "2.2.2"
   resolved "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab"
   integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==


Test patch:
diff --git a/scripts/atest.py b/scripts/atest.py
index 64ed3517..8998af0c 100644
--- a/scripts/atest.py
+++ b/scripts/atest.py
@@ -1,7 +1,7 @@
 """ Run acceptance tests with robot framework
 """
 
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 # pylint: disable=broad-except
diff --git a/src/ipyforcegraph/tests/__init__.py b/src/ipyforcegraph/tests/__init__.py
index de09291b..1be58b25 100644
--- a/src/ipyforcegraph/tests/__init__.py
+++ b/src/ipyforcegraph/tests/__init__.py
@@ -1,2 +1,2 @@
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
diff --git a/src/ipyforcegraph/tests/test_meta.py b/src/ipyforcegraph/tests/test_meta.py
index f30a0e53..71699f3a 100644
--- a/src/ipyforcegraph/tests/test_meta.py
+++ b/src/ipyforcegraph/tests/test_meta.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2022 ipyforcegraph contributors.
+# Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
 import ipyforcegraph