Repository: jupyrdf/ipyforcegraph (language: python)

Issue:
Native continuous colorscales/colormaps
## Elevator Pitch
It would be extremely helpful if `ipyforcegraph` supported continuous colormaps (e.g. `viridis`) as part of the Nunjucks templating. Users would be able to specify columns that contain continuous values (age, weight, etc.) and a colormap, and `ipyforcegraph` would be able to apply the color as part of the e.g. NodeShape behavior without requiring additional dependencies i.e. `matplotlib`. 

## Motivation
Bringing in additional dependencies to support styling with `ipyforcegraph` can complicate build chains, recipes, etc. It would be valuable to reduce complexity of leveraging ipyforcegraph to include common colormaps for continuous values, which are more complicated to implement than discrete maps (which can be easily added with e.g. dictionaries). 

## Design Ideas

Something akin to `{{ node.value | colormap('viridis') }}` would be extremely powerful.

Add DodoSource
## References

- continues #44
- continues #7

## Code changes

- [x] add some more demo deps
  - [x] `ipydatagrid`
  - [x] ~~`ipytree`~~ 
    - [x] already quite busy, wouldn't add much
  - [x] `ipylab`   
  - [x] updated `ipywidgets` and `jupyterlab_widgets`
    - [x] update serialization for strict JSON
- [x] add `DodoSource`
  - [x] find nodes and lnks
    - [x] tasks
    - [x] files
    - [x] subtasks 
    - [x] task dep
    - [x] folders-of-files
- [ ] example notebook 
  - [x] make panel
  - [x] load source
  - [x] make grids
  - [x] link grids and selection
  - [x] run tasks
    - [x] logs without killing UI
    - [x] without blocking kernel
  - [x] highlight 
    - [x] dependency paths following `file_dep` and `task_dep` links
    - [x] upstreams
    - [x] downstreams 
  - [x] collapse nodes and edges 
- [x] issues noticed while working on app
  - [x] handle in-place updates (for certain cases)
  - [x] handle `linkHandlers` and `nodeHandlers` better for facets
  - [x] fix multiple shapes with "canary" attributes (e.g. `Rectangle.width` and `Text.text`)
  - [x] add `line_dash` to more shapes (via HasStrokeAndFill) 
  - [x] fix center point of custom Rectangle and Ellipse shapes 
- [x] docs
  - [x] changelog
  - [x] clean up some hard-coded positions for facets in docs
  - [x] update `jupyterlite-core` and `pyodide-kernel`

## User-facing changes

- users of the binder demo will be able to try out the grid against an evolving system
- users of the lit demo will see:

  | note | screen | 
  |-|-|
  | custom shapes | ![image](https://user-images.githubusercontent.com/7581399/229208783-857e756c-d538-4bc5-8d08-ec8e4cbec0bc.png)
  | running tasks based on task selection | ![image](https://user-images.githubusercontent.com/7581399/227029751-999ee950-cd77-4543-b611-d31b8e34ba64.png)
  | ipylab icons | ![image](https://user-images.githubusercontent.com/7581399/228609912-1583802e-880a-453a-868a-a610c70bb974.png)
  | shortest path with particles |![image](https://user-images.githubusercontent.com/7581399/228954415-e612e336-b604-4372-b4fc-6a0ac8f4539f.png)
  | upstream/downstream highlight | ![image](https://user-images.githubusercontent.com/7581399/231546467-03bb44f7-c0c1-4709-b53b-c2f53d14d11b.png)
 



## Backwards-incompatible changes

- n/a


Discussion / hints:
From a discussion offline: adding more complexity to `Nunjucks` would likely hurt performance/debuggability. 

[bqscales](https://github.com/bqplot/bqscales) exists, but might not do what we want. 

If we have to implement it full-cloth, we would likely still lean on the d3 ecosystem, such as [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic), as a new sibling to `Nunjucks` and `Column`.

As a strawman:

```py
node_shape.color = ColorScale(
    column_name="value",
    min=fg.source.nodes.value.min(),
    max=fg.source.nodes.value.max(),
    named_scheme=ScaledColumn.COLORS.viridis
)
```

Probably have some other approaches for arbitrary values (e.g. `domain=["red", "blue"]`).

This may entail some lower-level `Scale` which can handle different kinds of things.
Try it on [![](https://jupyterlite.rtfd.io/en/latest/_static/badge.svg)](https://ipyforcegraph--68.org.readthedocs.build/en/68/_static/lab/index.html?path=_index.ipynb) :arrow_left: ReadTheDocs or Binder :arrow_right: [![](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/nrbgt/ipyforcegraph/gh-44-dodo-source?urlpath=lab/tree/examples/_index.ipynb)
Resolve with `networkx` incoming...
thanks for the review! :heart_eyes: 

> didn't see the `Dodo` notebooks in there.

Yep, they don't work in lite because `subprocess.Popen`. Also `doit` doesn't import, due to some unvendored stdlib packages... to that end, I started some playground stuff on [doitoml](https://doitoml.readthedocs.io/en/latest/demo.html), but if course _doit_ relies on `subprocess.Popen` as well, so only pure-python actions work.

> the between particles

will look into it. Trying to get fancy with non-blocking stuff. Got some ideas on how that could be improved.

> selection from datagrid

will look into it

>> selection from datagrid
>
> will look into it

oof, this is general failure, even setting it programmatically doesn't work.

```
node_selection.selected = [0]
# doesn't highlight `all`
```

the issue is that we don't update the `graphData.nodes._selected` when a selection update comes in, and then `node-selection` thing is getting clobbered by the fancy text junk.
fixed selection on 43202f1
>> the between particles
> will look into it. 

Ah, this might due to it actually being a bit more accurate now, as it will only show particles if there is a path of the form:

```
[file] --> file_dep --> task --> targets --> [other file]
```

(Or the reverse)

Initially, it kinda lied, as it would follow sibling paths like:

```
[file] --> file_dep --> task --> file_dep --> [other file]
```

So basically: a lot of the nodes aren't particularly sensitive to other nodes. If there's a concrete example, happy to look into it!
I've updated the label to show the path count, a la ![image](https://github.com/jupyrdf/ipyforcegraph/assets/7581399/b5a326cc-0bce-41ab-91de-0432f82a3b5e)

> > > the between particles
> > > will look into it.
> 
> Ah, this might due to it actually being a bit more accurate now, as it will only show particles if there is a path of the form:
> 
> ```
> [file] --> file_dep --> task --> targets --> [other file]
> ```
> 
> (Or the reverse)
> 
> Initially, it kinda lied, as it would follow sibling paths like:
> 
> ```
> [file] --> file_dep --> task --> file_dep --> [other file]
> ```
> 
> So basically: a lot of the nodes aren't particularly sensitive to other nodes. If there's a concrete example, happy to look into it!

Yeah, that makes sense.  No, I don't think it's worth it to go beyond what you've done.  It's working nicely!
I vote we pull the trigger.  The only thing I could find was that when you try to open some files, it says it can't find them.  Think it is for files that start with `.`?  Obviously, testing this on 🪟ers, so 🐧 may be fine...

![image](https://github.com/jupyrdf/ipyforcegraph/assets/1438114/b661b438-554d-4c10-bb8b-d05cb0998189)


Fix patch:
diff --git a/.github/locks/linux-64_dev_lab3.6_py3.11.conda.lock b/.github/locks/linux-64_dev_lab3.6_py3.11.conda.lock
index 0d627fcf..e7bd8f84 100644
--- a/.github/locks/linux-64_dev_lab3.6_py3.11.conda.lock
+++ b/.github/locks/linux-64_dev_lab3.6_py3.11.conda.lock
@@ -74,7 +74,7 @@ https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-ca-2023.01.01-
 https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-gb-2023.01.01-hd8ed1ab_0.conda#11f8c5ac6a9b675e3f9dc104d542b1e5
 https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-us-2023.01.01-hd8ed1ab_0.conda#6b5dc33511564bd4556338ad624c272c
 https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-za-2023.01.01-hd8ed1ab_0.conda#4ae73b415a08dab577bf208f9a79d407
-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/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
@@ -86,7 +86,7 @@ https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#
 https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535
 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54
 https://conda.anaconda.org/conda-forge/linux-64/c-ares-1.18.1-h7f98852_0.tar.bz2#f26ef8098fab1f719c91eb760d63381a
-https://conda.anaconda.org/conda-forge/linux-64/firefox-102.10.0esr-hcb278e6_0.conda#057cc9aca5cdf3ed6d4247a1d98e5568
+https://conda.anaconda.org/conda-forge/linux-64/firefox-102.11.0esr-h59595ed_0.conda#b8a18b5550c271147a9d048368db4093
 https://conda.anaconda.org/conda-forge/linux-64/geckodriver-0.33.0-hd2f7af9_0.conda#83664049f2b276cc23bd67d41eb9a4ee
 https://conda.anaconda.org/conda-forge/linux-64/gettext-0.21.1-h27087fc_0.tar.bz2#14947d8770185e5153fdd04d4673ed37
 https://conda.anaconda.org/conda-forge/linux-64/icu-70.1-h27087fc_0.tar.bz2#87473a15119779e021c314249d4b4aed
@@ -112,7 +112,7 @@ https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-hcb278e6_1.conda#8b9
 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.52.0-h61bc06f_0.conda#613955a50485812985c059e7b269f42e
-https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 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-hca2bb57_4.conda#bb808b654bdc3c783deaf107a2ffb503
 https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.19.2-h32600fe_2.conda#326f46f36d15c44cff5f81d505cb717f
@@ -135,10 +135,10 @@ https://conda.anaconda.org/conda-forge/linux-64/python-3.11.3-h2755cc3_0_cpython
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -177,7 +177,7 @@ https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.3-py311h64a7726_0.conda#f1d507e1a5f1151845f7818ceb02ba9f
-https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.11-py311h34b1e23_0.conda#40b9902e930c9ec2a7a761aea109704d
+https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.12-py311h34b1e23_0.conda#38293fbb4e657a3cc911afa3f45b018e
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -206,7 +206,7 @@ https://conda.anaconda.org/conda-forge/linux-64/pyzmq-25.0.2-py311hd6ccaeb_0.con
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2#d337886e38f965bf97aaec382ff6db00
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-validator-0.1.1-pyh9f0ad1d_0.tar.bz2#912a71cc01012ee38e6b90ddd561e36f
 https://conda.anaconda.org/conda-forge/noarch/robotframework-6.0.2-pyhd8ed1ab_1.conda#b4dcead8c5a99a14733d9b1ba5b7db09
-https://conda.anaconda.org/conda-forge/linux-64/ruff-0.0.264-py311h7145743_0.conda#1af634f6308c075d612f9b85e2e450e9
+https://conda.anaconda.org/conda-forge/linux-64/ruff-0.0.265-py311h7145743_0.conda#d1bc56f499b7a0ea81b1e7214ee2147f
 https://conda.anaconda.org/conda-forge/noarch/send2trash-1.8.2-pyh41d4057_0.conda#ada5a17adcd10be4fc7e37e4166ba0e2
 https://conda.anaconda.org/conda-forge/noarch/setuptools-67.7.2-pyhd8ed1ab_0.conda#3b68bc43ec6baa48f7354a446267eefe
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
@@ -268,7 +268,7 @@ https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2
 https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2#330448ce4403cc74990ac07c555942a1
 https://conda.anaconda.org/conda-forge/noarch/pip-23.1.2-pyhd8ed1ab_0.conda#7288da0d36821349cf1126e8670292df
 https://conda.anaconda.org/conda-forge/noarch/py2vega-0.6.1-pyhd8ed1ab_0.tar.bz2#07594783f950301f5943e6d080ffb4eb
-https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.1-pyhd8ed1ab_0.conda#171a4201299a33a2ff022afe9f821417
+https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.2-pyhd8ed1ab_0.conda#a6099de9e7ea9f7bea14e2a093f07881
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/noarch/rfc3339-validator-0.1.4-pyhd8ed1ab_0.tar.bz2#fed45fc5ea0813240707998abe49f520
 https://conda.anaconda.org/conda-forge/noarch/robotframework-pythonlibcore-4.1.2-pyhd8ed1ab_0.conda#3af043636b92ad0317a234544b30a4a8
@@ -291,7 +291,7 @@ https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.6.0-hd8ed1ab_
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_terminals-0.4.4-pyhd8ed1ab_1.conda#7c0965e1d4a0ee1529e8eaa03a78a5b3
 https://conda.anaconda.org/conda-forge/noarch/mdit-py-plugins-0.3.5-pyhd8ed1ab_0.conda#9eeb66a24c8f6d950eb55a9f1128da20
-https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_0.conda#de0bcfeb3c829f630399dc6b5ab829e1
+https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_1.conda#37f841a3140999c4735f7d8091072bea
 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.5.0-pyhd8ed1ab_0.conda#6c36f1c42dd0069b7f23acc74f19be46
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.3.1-pyhd8ed1ab_0.conda#547c7de697ec99b494a28ddde185b5a4
 https://conda.anaconda.org/conda-forge/noarch/rich-13.3.5-pyhd8ed1ab_0.conda#2e40a02ad28e34f26cee2a72042843db
@@ -334,12 +334,12 @@ https://conda.anaconda.org/conda-forge/noarch/jupyterlite-pyodide-kernel-0.0.8-p
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/nbstripout-0.6.1-pyhd8ed1ab_0.tar.bz2#53913d98739527409e0f3227ed7eef7d
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-23.3.0-hd8ed1ab_1.conda#62cc29ee11300ae8a587ff6396e78b62
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh210e3f2_0.conda#1b463a5f4b7c83f509f6a1168a6ef554
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh210e3f2_0.conda#a9d13f9aee96fd4650928ac0302b0bf8
 https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.6.1-pyhd8ed1ab_0.conda#2e360820ae68e3d28e1a5a9d2714ca5c
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/nbqa-1.7.0-pyhd8ed1ab_1.conda#65da1779c33b7fa51a0aba5c30758c5e
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-1.0.1-pyhd8ed1ab_0.conda#43ec7b3627237e5fe23413e314e8ba4c
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda#99c98318c8646b08cc764f90ce98906e
@@ -349,7 +349,7 @@ https://conda.anaconda.org/conda-forge/noarch/autodoc-traits-1.1.0-pyhd8ed1ab_0.
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
 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-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.13.3-pyhd8ed1ab_0.conda#07aca5f2dea315dcc16680d6891e9056
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
@@ -361,7 +361,7 @@ https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.2-pyhd8ed1ab_0.conda#40190b7d06f86b63d28fa78aaa39c023
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/linux-64_lock.conda.lock b/.github/locks/linux-64_lock.conda.lock
index 29fb29fd..85e60097 100644
--- a/.github/locks/linux-64_lock.conda.lock
+++ b/.github/locks/linux-64_lock.conda.lock
@@ -10,7 +10,7 @@
 
 @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.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 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
@@ -44,7 +44,7 @@ https://conda.anaconda.org/conda-forge/linux-64/expat-2.5.0-hcb278e6_1.conda#8b9
 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.52.0-h61bc06f_0.conda#613955a50485812985c059e7b269f42e
 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_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 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.4-hfdac1af_0.conda#241845899caff54ac1d2b3102ad988cf
 https://conda.anaconda.org/conda-forge/linux-64/pcre2-10.40-hc3806b6_0.tar.bz2#69e2c796349cd9b273890bee0febfe1b
@@ -58,7 +58,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libglib-2.76.2-hebfc3b9_0.conda#
 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.3-h2755cc3_0_cpython.conda#37005ea5f68df6a8a381b70cf4d4a160
 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.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -99,7 +99,7 @@ https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.6.0-pyha770c7
 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.3.1-hcea66bb_2.conda#6916be1fb023d7f8e34dbd55068a8eff
-https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.17.22-py311h459d7ec_0.conda#9cf446cb1367ed3ce82c8635fe7daa02
+https://conda.anaconda.org/conda-forge/linux-64/ruamel.yaml-0.17.24-py311h459d7ec_0.conda#fd302595bcbab281511a17808524b5a0
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392
 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-40.0.2-py311h9b4c7bb_0.conda#4df4df92db0b9168c11b72460baec870
diff --git a/.github/locks/osx-64_dev_lab3.6_py3.11.conda.lock b/.github/locks/osx-64_dev_lab3.6_py3.11.conda.lock
index 5edf5c88..e92bfe77 100644
--- a/.github/locks/osx-64_dev_lab3.6_py3.11.conda.lock
+++ b/.github/locks/osx-64_dev_lab3.6_py3.11.conda.lock
@@ -75,8 +75,8 @@ https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-us-2023.01.01-
 https://conda.anaconda.org/conda-forge/noarch/aoo-mozilla-en-dict-za-2023.01.01-hd8ed1ab_0.conda#4ae73b415a08dab577bf208f9a79d407
 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.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-haf1e3a3_1.tar.bz2#79dc2be110b2a3d1e97ec21f691c50ad
 https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.5.0-hf0c8a7f_1.conda#6c81cb022780ee33435cca0127dd43c9
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
@@ -93,13 +93,13 @@ https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.11-3_cp311.conda#5e0a
 https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda#939e3e74d8be4dac89ce83b20de2492a
 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/firefox-102.10.0esr-hf0c8a7f_0.conda#52e68cb8ad4770651020fcab425b0b99
+https://conda.anaconda.org/conda-forge/osx-64/firefox-102.11.0esr-he965462_0.conda#bf6f4386389cee37e4bd9cd55e3b663c
 https://conda.anaconda.org/conda-forge/osx-64/geckodriver-0.33.0-hf46a32e_0.conda#897200360380560ac85cf0756161dd78
 https://conda.anaconda.org/conda-forge/osx-64/gettext-0.21.1-h8a4c099_0.tar.bz2#1e3aff29ce703d421c43f371ad676cc5
 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/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3
-https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.4-hf0c8a7f_0.conda#aa04f7143228308662696ac24023f991
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
 https://conda.anaconda.org/conda-forge/osx-64/pcre2-10.40-h1c4e4bc_0.tar.bz2#e0f80c8f3a0352a54eddfe59cd2b25b1
@@ -121,10 +121,10 @@ https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.b
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -162,7 +162,7 @@ https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.11-py311h52ff4d3_0.conda#74ea1a8d16b3290cd492da6f683ef8fd
+https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.12-py311h52ff4d3_0.conda#1acaddcf7e60378c29b693bb4360c6b2
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -190,7 +190,7 @@ https://conda.anaconda.org/conda-forge/osx-64/pyzmq-25.0.2-py311habfacb3_0.conda
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2#d337886e38f965bf97aaec382ff6db00
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-validator-0.1.1-pyh9f0ad1d_0.tar.bz2#912a71cc01012ee38e6b90ddd561e36f
 https://conda.anaconda.org/conda-forge/noarch/robotframework-6.0.2-pyhd8ed1ab_1.conda#b4dcead8c5a99a14733d9b1ba5b7db09
-https://conda.anaconda.org/conda-forge/osx-64/ruff-0.0.264-py311hbf57787_0.conda#ed9f987ff258d043f82e04ea29617f48
+https://conda.anaconda.org/conda-forge/osx-64/ruff-0.0.265-py311hbf57787_0.conda#90be58e369b6a5617b68b3105b464ca2
 https://conda.anaconda.org/conda-forge/noarch/setuptools-67.7.2-pyhd8ed1ab_0.conda#3b68bc43ec6baa48f7354a446267eefe
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
 https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.0-pyhd8ed1ab_0.tar.bz2#dd6cbc539e74cb1f430efbd4575b9303
@@ -253,7 +253,7 @@ https://conda.anaconda.org/conda-forge/noarch/pexpect-4.8.0-pyh1a96a4e_2.tar.bz2
 https://conda.anaconda.org/conda-forge/noarch/pip-23.1.2-pyhd8ed1ab_0.conda#7288da0d36821349cf1126e8670292df
 https://conda.anaconda.org/conda-forge/noarch/py2vega-0.6.1-pyhd8ed1ab_0.tar.bz2#07594783f950301f5943e6d080ffb4eb
 https://conda.anaconda.org/conda-forge/osx-64/pyobjc-core-9.1.1-py311hfd07503_0.conda#ba333461302daaea2dfce2d5223c876e
-https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.1-pyhd8ed1ab_0.conda#171a4201299a33a2ff022afe9f821417
+https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.2-pyhd8ed1ab_0.conda#a6099de9e7ea9f7bea14e2a093f07881
 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/rfc3339-validator-0.1.4-pyhd8ed1ab_0.tar.bz2#fed45fc5ea0813240707998abe49f520
@@ -313,7 +313,7 @@ https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.2.0-pyhd8ed1ab_0.
 https://conda.anaconda.org/conda-forge/noarch/jupyterlite-core-0.1.0-pyhd8ed1ab_0.conda#c848221f9bd434fb89fa992214e5e64a
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.8.0-pyhd8ed1ab_0.conda#1ca43103a08456b19222d93fd9d119ac
 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-2.0.1-py311hab14417_0.conda#cd9a03d6202f518e2fcb6720ddba19f7
+https://conda.anaconda.org/conda-forge/osx-64/pandas-2.0.1-py311hab14417_1.conda#618f01d1356c3443fa11378ab44dd7a4
 https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.38-hd8ed1ab_0.conda#45b74f64d8808eda7e6f6e6b1d641fd2
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/pytest-json-report-1.5.0-pyhd8ed1ab_0.tar.bz2#837e335fa428cf7c784ee2e80594506c
@@ -325,12 +325,12 @@ https://conda.anaconda.org/conda-forge/noarch/jupyterlite-pyodide-kernel-0.0.8-p
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/nbstripout-0.6.1-pyhd8ed1ab_0.tar.bz2#53913d98739527409e0f3227ed7eef7d
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-23.3.0-hd8ed1ab_1.conda#62cc29ee11300ae8a587ff6396e78b62
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh736e0ef_0.conda#3bbe4a71a9d5d8e13c1504e3cd077b32
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh736e0ef_0.conda#6568402ca7540ad5b352fb51ffe17b51
 https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.6.1-pyhd8ed1ab_0.conda#2e360820ae68e3d28e1a5a9d2714ca5c
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/nbqa-1.7.0-pyhd8ed1ab_1.conda#65da1779c33b7fa51a0aba5c30758c5e
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-1.0.1-pyhd8ed1ab_0.conda#43ec7b3627237e5fe23413e314e8ba4c
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda#99c98318c8646b08cc764f90ce98906e
@@ -340,7 +340,7 @@ https://conda.anaconda.org/conda-forge/noarch/autodoc-traits-1.1.0-pyhd8ed1ab_0.
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
 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-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.13.3-pyhd8ed1ab_0.conda#07aca5f2dea315dcc16680d6891e9056
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
@@ -352,7 +352,7 @@ https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.2-pyhd8ed1ab_0.conda#40190b7d06f86b63d28fa78aaa39c023
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/osx-64_lock.conda.lock b/.github/locks/osx-64_lock.conda.lock
index b5773248..83a7034c 100644
--- a/.github/locks/osx-64_lock.conda.lock
+++ b/.github/locks/osx-64_lock.conda.lock
@@ -11,9 +11,9 @@
 @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.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
 https://conda.anaconda.org/conda-forge/osx-64/icu-72.1-h7336db1_0.conda#c9689510a50a4bb2ae978421671a125e
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libev-4.33-haf1e3a3_1.tar.bz2#79dc2be110b2a3d1e97ec21f691c50ad
 https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.5.0-hf0c8a7f_1.conda#6c81cb022780ee33435cca0127dd43c9
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
@@ -30,7 +30,7 @@ https://conda.anaconda.org/conda-forge/osx-64/yaml-0.2.5-h0d85af4_2.tar.bz2#d7e0
 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/libedit-3.1.20191231-h0678c8f_2.tar.bz2#6016a8a1d0e63cac3de2c352cd40208b
 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_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.4-h554bb67_0.conda#003fef825b16c26c44d97e115bf8840e
 https://conda.anaconda.org/conda-forge/osx-64/lz4-c-1.9.4-hf0c8a7f_0.conda#aa04f7143228308662696ac24023f991
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
@@ -46,7 +46,7 @@ https://conda.anaconda.org/conda-forge/osx-64/libssh2-1.10.0-h47af595_3.tar.bz2#
 https://conda.anaconda.org/conda-forge/osx-64/python-3.11.3-h99528f9_0_cpython.conda#c3291f9411424fc587d53a2ea57fb075
 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.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -85,7 +85,7 @@ https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-6.6.0-pyha770c7
 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.3.1-h9d281b0_2.conda#07ce93400f49f98628759b9c08a7bf72
-https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.22-py311h2725bcf_0.conda#eb9618c37676eee4678b7def9e0f5385
+https://conda.anaconda.org/conda-forge/osx-64/ruamel.yaml-0.17.24-py311h2725bcf_0.conda#da2d8a861a0d448e33ed95eb045baf0e
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392
 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-40.0.2-py311h61927ef_0.conda#724b75f84bb1b5d932627d090a527168
diff --git a/.github/locks/win-64_dev_lab3.6_py3.11.conda.lock b/.github/locks/win-64_dev_lab3.6_py3.11.conda.lock
index 6ddd695f..72875158 100644
--- a/.github/locks/win-64_dev_lab3.6_py3.11.conda.lock
+++ b/.github/locks/win-64_dev_lab3.6_py3.11.conda.lock
@@ -66,7 +66,7 @@
 #   - twine
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/win-64/git-2.40.1-h57928b3_0.conda#bf81e55736ff8937a3b3f4576a96ea9a
 https://conda.anaconda.org/conda-forge/win-64/intel-openmp-2023.1.0-h57928b3_46319.conda#dbc4636f419722fbf3ab6501377228ba
 https://conda.anaconda.org/conda-forge/win-64/libexpat-2.5.0-h63175ca_1.conda#636cc3cbbd2e28bcfd2f73b2044aac2c
@@ -83,12 +83,12 @@ https://conda.anaconda.org/conda-forge/win-64/m2-gcc-libs-5.3.0-4.tar.bz2#51f9be
 https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb25d44b_16.conda#ea326b37e3bd6d2616988e09f3a9396c
 https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.34.31931-hed1258a_16.conda#0374eae69b6dbfb27c3dc27167109eb4
 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9
-https://conda.anaconda.org/conda-forge/win-64/firefox-102.10.0esr-h63175ca_0.conda#a53c1459c65768ba48481a186ceed34b
+https://conda.anaconda.org/conda-forge/win-64/firefox-102.11.0esr-h63175ca_0.conda#12ea043f0413a98078731e9f0657c776
 https://conda.anaconda.org/conda-forge/win-64/geckodriver-0.33.0-h611cf2b_0.conda#e5ad5ec7f6140c1fdf9bd2a7927a4f91
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
 https://conda.anaconda.org/conda-forge/win-64/libsodium-1.0.18-h8d14728_1.tar.bz2#5c1fb45b5e2912c19098750ae8a32604
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda#e34720eb20a33fc3bfb8451dd837ab7a
 https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-he774522_1000.tar.bz2#d5cf4b7eaa52316f135eed9e8548ad57
@@ -106,10 +106,10 @@ https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h12be248_6.conda#628265
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/alabaster-0.7.13-pyhd8ed1ab_0.conda#06006184e203b61d3525f90de394471e
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -145,7 +145,7 @@ https://conda.anaconda.org/conda-forge/noarch/mypy_extensions-1.0.0-pyha770c72_0
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.11-py311h5443569_0.conda#9c1bd04b7c98b86b362a0f0c9716d34d
+https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.12-py311h5443569_0.conda#6c843e80610cfbf3f4c59a56d9a25d58
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -174,7 +174,7 @@ https://conda.anaconda.org/conda-forge/win-64/pyzmq-25.0.2-py311h7b3f143_0.conda
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-2.0.0-pyhd8ed1ab_0.tar.bz2#d337886e38f965bf97aaec382ff6db00
 https://conda.anaconda.org/conda-forge/noarch/rfc3986-validator-0.1.1-pyh9f0ad1d_0.tar.bz2#912a71cc01012ee38e6b90ddd561e36f
 https://conda.anaconda.org/conda-forge/noarch/robotframework-6.0.2-pyhd8ed1ab_1.conda#b4dcead8c5a99a14733d9b1ba5b7db09
-https://conda.anaconda.org/conda-forge/win-64/ruff-0.0.264-py311hc14472d_0.conda#bfa669ebbd12304f111ccb62b59233b1
+https://conda.anaconda.org/conda-forge/win-64/ruff-0.0.265-py311hc14472d_0.conda#d8934881181b5b3bcc8f4acbb37b443e
 https://conda.anaconda.org/conda-forge/noarch/setuptools-67.7.2-pyhd8ed1ab_0.conda#3b68bc43ec6baa48f7354a446267eefe
 https://conda.anaconda.org/conda-forge/noarch/six-1.16.0-pyh6c4a22f_0.tar.bz2#e5f25f8dbc060e9a8d912e432202afc2
 https://conda.anaconda.org/conda-forge/noarch/sniffio-1.3.0-pyhd8ed1ab_0.tar.bz2#dd6cbc539e74cb1f430efbd4575b9303
@@ -235,7 +235,7 @@ https://conda.anaconda.org/conda-forge/win-64/mypy-1.2.0-py311ha68e1ae_0.conda#f
 https://conda.anaconda.org/conda-forge/noarch/outcome-1.2.0-pyhd8ed1ab_0.tar.bz2#3dbb9ece72652131f12d66e889da7c0a
 https://conda.anaconda.org/conda-forge/noarch/pip-23.1.2-pyhd8ed1ab_0.conda#7288da0d36821349cf1126e8670292df
 https://conda.anaconda.org/conda-forge/noarch/py2vega-0.6.1-pyhd8ed1ab_0.tar.bz2#07594783f950301f5943e6d080ffb4eb
-https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.1-pyhd8ed1ab_0.conda#171a4201299a33a2ff022afe9f821417
+https://conda.anaconda.org/conda-forge/noarch/pyproject-fmt-0.11.2-pyhd8ed1ab_0.conda#a6099de9e7ea9f7bea14e2a093f07881
 https://conda.anaconda.org/conda-forge/noarch/pysocks-1.7.1-pyh0701188_6.tar.bz2#56cd9fe388baac0e90c7149cfac95b60
 https://conda.anaconda.org/conda-forge/noarch/python-dateutil-2.8.2-pyhd8ed1ab_0.tar.bz2#dd999d1cc9f79e67dbb855c8924c7984
 https://conda.anaconda.org/conda-forge/win-64/python-libarchive-c-4.0-py311h1ea47a8_2.tar.bz2#587f3af8e6a1d545a1b3b5a2617435f7
@@ -307,15 +307,15 @@ https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#
 https://conda.anaconda.org/conda-forge/noarch/nbstripout-0.6.1-pyhd8ed1ab_0.tar.bz2#53913d98739527409e0f3227ed7eef7d
 https://conda.anaconda.org/conda-forge/win-64/numpy-1.24.3-py311h0b4df5a_0.conda#7efb2d8d15616284d8496235d2731ebf
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/black-jupyter-23.3.0-hd8ed1ab_1.conda#62cc29ee11300ae8a587ff6396e78b62
 https://conda.anaconda.org/conda-forge/noarch/flit-3.8.0-pyhd8ed1ab_0.tar.bz2#d37c34176396c5402cf80c32e67731b7
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh025b116_0.conda#4d594953555f43826532ab5c5f7754f5
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh025b116_0.conda#94be25e827144cc4263ee2c81ae01bd2
 https://conda.anaconda.org/conda-forge/noarch/jupyter-cache-0.6.1-pyhd8ed1ab_0.conda#2e360820ae68e3d28e1a5a9d2714ca5c
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/nbqa-1.7.0-pyhd8ed1ab_1.conda#65da1779c33b7fa51a0aba5c30758c5e
 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-2.0.1-py311hf63dbb6_0.conda#00052d983770902d3dac8097c1b82e67
+https://conda.anaconda.org/conda-forge/win-64/pandas-2.0.1-py311hf63dbb6_1.conda#509562c4360e4cdd30ff1c2d9789f205
 https://conda.anaconda.org/conda-forge/noarch/requests-cache-1.0.1-pyhd8ed1ab_0.conda#43ec7b3627237e5fe23413e314e8ba4c
 https://conda.anaconda.org/conda-forge/noarch/requests-toolbelt-1.0.0-pyhd8ed1ab_0.conda#99c98318c8646b08cc764f90ce98906e
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
@@ -324,7 +324,7 @@ https://conda.anaconda.org/conda-forge/noarch/autodoc-traits-1.1.0-pyhd8ed1ab_0.
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
 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-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/pydata-sphinx-theme-0.13.3-pyhd8ed1ab_0.conda#07aca5f2dea315dcc16680d6891e9056
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/sphinx-autobuild-2021.3.14-pyhd8ed1ab_0.tar.bz2#1909f784dc37b4ab97afe2c95aeeabaa
@@ -336,7 +336,7 @@ https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
 https://conda.anaconda.org/conda-forge/noarch/myst-nb-0.17.2-pyhd8ed1ab_0.conda#40190b7d06f86b63d28fa78aaa39c023
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/win-64_lock.conda.lock b/.github/locks/win-64_lock.conda.lock
index 516f181b..8fef2435 100644
--- a/.github/locks/win-64_lock.conda.lock
+++ b/.github/locks/win-64_lock.conda.lock
@@ -9,7 +9,7 @@
 #   - python >=3.11,<3.12
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/win-64/libexpat-2.5.0-h63175ca_1.conda#636cc3cbbd2e28bcfd2f73b2044aac2c
 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
@@ -22,7 +22,7 @@ https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c0
 https://conda.anaconda.org/conda-forge/win-64/fmt-9.1.0-h181d51b_0.tar.bz2#31a20cf261b2bd0a76d670db1b3e6fa1
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/lz4-c-1.9.4-hcfcfb64_0.conda#e34720eb20a33fc3bfb8451dd837ab7a
 https://conda.anaconda.org/conda-forge/win-64/lzo-2.10-he774522_1000.tar.bz2#d5cf4b7eaa52316f135eed9e8548ad57
@@ -41,7 +41,7 @@ https://conda.anaconda.org/conda-forge/win-64/reproc-cpp-14.2.4-h63175ca_0.conda
 https://conda.anaconda.org/conda-forge/win-64/zstd-1.5.2-h12be248_6.conda#62826565682d013b3e2346aaf7bded0e
 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.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -84,7 +84,7 @@ https://conda.anaconda.org/conda-forge/noarch/jaraco.classes-3.2.3-pyhd8ed1ab_0.
 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.3.1-h8a7d157_2.conda#f3dea6dd537d0b6dbb9a86e5ffbf74f5
 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.22-py311ha68e1ae_0.conda#d2d57bb83a5996ad9a2d7438136e7181
+https://conda.anaconda.org/conda-forge/win-64/ruamel.yaml-0.17.24-py311ha68e1ae_0.conda#dbb8c2bdbacdb214c0b827ac9eaa504e
 https://conda.anaconda.org/conda-forge/noarch/typing-extensions-4.5.0-hd8ed1ab_0.conda#b3c594fde1a80a1fc3eb9cc4a5dfe392
 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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ebd31734..6cfd55f8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,8 @@
     simulation engine (e.g. `x` and `y`) and custom columns, such as created by
     `Selection` behaviors
   - `link_id_column` is required if the number and or order of links change
+- adds `ContinuousColor` and `OrdinalColor` color schemes, supported by
+  `d3-scale-chromatic`
 
 ### `@jupyrdf/jupyter-forcegraph 0.3.2`
 
diff --git a/docs/dictionary.txt b/docs/dictionary.txt
index e5554e70..ace915b5 100644
--- a/docs/dictionary.txt
+++ b/docs/dictionary.txt
@@ -5,16 +5,29 @@ args
 backend
 BaseD3Force
 bool
+brbg
+BrBG
+bugn
+BuGn
+bupu
+BuPu
+category10
 CenterForce
 ci
+cividis
+Cividis
 ClusterForce
 CollisionForce
 composable
 conda
+ContinuousColor
 cooldown
+cubehelixdefault
+CubehelixDefault
 d3
 DAGForce
 DAGMode
+dark2
 dataframe
 DataFrame
 dataframes
@@ -29,6 +42,8 @@ ForceBase
 forcegraph
 ForceGraph
 ForceGraph3D
+gnbu
+GnBu
 GraphData
 GraphForces
 GraphImage
@@ -70,8 +85,25 @@ NodeTooltip
 npm
 numpy
 nunjucks
+OrdinalColor
+orrd
+OrRd
 PandasType
+pastel1
+pastel2
+piyg
+PiYG
+prgn
+PRGn
 PRs
+pubu
+PuBu
+pubugn
+PuBuGn
+puor
+PuOr
+purd
+PuRd
 py
 PyData
 pypi
@@ -79,12 +111,28 @@ PyPI
 quadtrees
 qualname
 RadialForce
+rdbu
+RdBu
+rdgy
+RdGy
+rdpu
+RdPu
+rdylbu
+RdYlBu
+rdylgn
+RdYlGn
 ReadTheDocs
 repr
 rgba
+set1
+set2
+set3
 ShapeBase
+sinebow
+Sinebow
 sqlite3
 str
+tableau10
 TBD
 TODO
 traitleted
@@ -93,8 +141,18 @@ traittypes
 TypedTuple
 TypeScript
 vasturiano
+viridis
+Viridis
 warmup
 WidgetSource
 XForce
 YForce
+ylgn
+YlGn
+ylgnbu
+YlGnBu
+ylorbr
+YlOrBr
+ylorrd
+YlOrRd
 ZForce
diff --git a/docs/reference/index.md b/docs/reference/index.md
index a7c0df13..15f57dbc 100644
--- a/docs/reference/index.md
+++ b/docs/reference/index.md
@@ -10,6 +10,7 @@ widgets
 sources
 behaviors
 forces
+scales
 ```
 
 ## Bases
diff --git a/docs/reference/scales.md b/docs/reference/scales.md
new file mode 100644
index 00000000..7e232e0c
--- /dev/null
+++ b/docs/reference/scales.md
@@ -0,0 +1,6 @@
+# Scales
+
+```{eval-rst}
+.. currentmodule:: ipyforcegraph
+.. automodule:: ipyforcegraph.behaviors.scales
+```
diff --git a/examples/Scales.ipynb b/examples/Scales.ipynb
new file mode 100644
index 00000000..e490770d
--- /dev/null
+++ b/examples/Scales.ipynb
@@ -0,0 +1,237 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "a1c52cbc-6187-4353-a195-e133b7e64349",
+   "metadata": {},
+   "source": [
+    "# ⚖️ Scales\n",
+    "\n",
+    "Scales, provided by [`d3-scale-chromatic`](https://github.com/d3/d3-scale-chromatic)\n",
+    "provide an efficient way to use pre-calcluated values for a number color-based node and\n",
+    "link [shape](./Shapes.ipynb) properties.\n",
+    "\n",
+    "Scales have a _domain_ (the expected values) and a _range_ (the colors to draw).\n",
+    "\n",
+    "Some experimentation may be needed to find an appropriate combination of these settings\n",
+    "for a given graph's data."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "077126e8-e6b9-4ab7-8cf4-11a15d102c7c",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "if __name__ == \"__main__\" and \"pyodide\" in __import__(\"sys\").modules:\n",
+    "    %pip install -q -r requirements.txt"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "ae9f6917-f608-43de-8107-6d6a56c70d45",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "import ipywidgets as W\n",
+    "import traitlets as T\n",
+    "from ipyforcegraph import behaviors as B\n",
+    "from ipyforcegraph import graphs as G\n",
+    "from ipyforcegraph.behaviors import scales as SC"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "51576d0e-1f48-4c4b-ada9-7c1351097436",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "fg = G.ForceGraph(layout=dict(flex=\"1\", height=\"100%\"))\n",
+    "controls = W.VBox(layout=dict(min_width=\"25em\", flex=\"0\"))\n",
+    "W.HBox(\n",
+    "    [controls, fg],\n",
+    "    layout=dict(\n",
+    "        min_height=\"400px\", height=\"100%\", flex=\"1\", overflow=\"hidden\", display=\"flex\"\n",
+    "    ),\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "65584c5a-3653-4f00-8013-b5969720b853",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "n = 100\n",
+    "with fg.source.hold_trait_notifications():\n",
+    "    fg.source.nodes = [{\"id\": i, \"value\": i / n} for i in range(n)]\n",
+    "    fg.source.links = sum(\n",
+    "        [\n",
+    "            [\n",
+    "                {\"id\": i, \"source\": i, \"target\": i - 1 if i else n - 1},\n",
+    "                {\"id\": i, \"source\": i, \"target\": i % 5, \"group\": i % 7},\n",
+    "            ]\n",
+    "            for i in range(n)\n",
+    "        ],\n",
+    "        [],\n",
+    "    )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "863ece12-21ba-4f72-8067-95f87140292b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "ns = B.NodeShapes()\n",
+    "ls = B.LinkShapes()\n",
+    "fg.behaviors = [ns, ls]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e166c0cd-b22c-48a6-8cfd-9c68de02cb2b",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def make_a_scheme_picker(enum):\n",
+    "    return W.SelectionSlider(\n",
+    "        description=\"scheme\", options={v.name: v.value for v in enum}\n",
+    "    )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "586d56b5-dae2-4333-8250-ad2b70a3781a",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def make_a_domain_range(scale):\n",
+    "    table = W.VBox()\n",
+    "\n",
+    "    def update_scale(*_):\n",
+    "        scale.domain = [row.children[1].value for row in table.children]\n",
+    "        scale.range = [row.children[2].value for row in table.children]\n",
+    "\n",
+    "    def remove_row(row):\n",
+    "        table.children = [c for c in table.children if c != row]\n",
+    "        row.close()\n",
+    "\n",
+    "    def add_row(*_):\n",
+    "        btn_remove_row = W.Button(\n",
+    "            icon=\"trash\", button_style=\"danger\", layout=dict(flex=\"0\", max_width=\"3em\")\n",
+    "        )\n",
+    "        d = W.FloatText(layout=dict(flex=\"1\", max_width=\"4em\"))\n",
+    "        r = W.ColorPicker(layout=dict(flex=\"1\", width=\"unset\"))\n",
+    "        d.observe(update_scale)\n",
+    "        r.observe(update_scale)\n",
+    "        row = W.HBox([btn_remove_row, d, r])\n",
+    "        btn_remove_row.on_click(lambda *_: remove_row(row))\n",
+    "        table.children = [*table.children, row]\n",
+    "        update_scale()\n",
+    "\n",
+    "    btn_add_row = W.Button(icon=\"plus\", description=\"add row\")\n",
+    "    btn_add_row.on_click(add_row)\n",
+    "    ui = W.VBox([btn_add_row, table])\n",
+    "    return ui"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bfcf42f9-f793-49c6-9f87-1f3aa9a16bfd",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def make_a_scale_picker(behavior, column, domain):\n",
+    "    c_scale = SC.ContinuousColor(\n",
+    "        column, scheme=SC.ContinuousColor.Scheme.viridis, domain=domain\n",
+    "    )\n",
+    "    c_scheme = make_a_scheme_picker(SC.ContinuousColor.Scheme)\n",
+    "    c_ui = W.VBox([c_scheme])\n",
+    "    T.link((c_scale, \"scheme\"), (c_scheme, \"value\"))\n",
+    "\n",
+    "    o_scale = SC.OrdinalColor(\n",
+    "        column, scheme=SC.OrdinalColor.Scheme.accent, domain=domain\n",
+    "    )\n",
+    "    o_scheme = make_a_scheme_picker(SC.OrdinalColor.Scheme)\n",
+    "    o_ui = W.VBox([o_scheme])\n",
+    "    T.link((o_scale, \"scheme\"), (o_scheme, \"value\"))\n",
+    "\n",
+    "    m_scale = SC.OrdinalColor(column)\n",
+    "    m_domain_range = make_a_domain_range(m_scale)\n",
+    "    m_ui = W.VBox([m_domain_range])\n",
+    "\n",
+    "    tabs = W.Tab([c_ui, o_ui, m_ui], titles=[\"continuous\", \"ordinal\", \"manual\"])\n",
+    "\n",
+    "    T.dlink(\n",
+    "        (tabs, \"selected_index\"),\n",
+    "        (behavior, \"color\"),\n",
+    "        lambda i: [c_scale, o_scale, m_scale][i],\n",
+    "    )\n",
+    "    return tabs"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1f45e2a6-c018-4a96-a52a-0df24cd1fcc7",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "controls.children = [\n",
+    "    W.Label(\"nodes\"),\n",
+    "    make_a_scale_picker(ns, \"value\", (0.0, 1.0)),\n",
+    "    W.Label(\"links\"),\n",
+    "    make_a_scale_picker(ls, \"group\", (0, 7)),\n",
+    "]"
+   ]
+  }
+ ],
+ "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.3"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/_index.ipynb b/examples/_index.ipynb
index 84c2d7a1..85187346 100644
--- a/examples/_index.ipynb
+++ b/examples/_index.ipynb
@@ -234,7 +234,8 @@
     "- [🏋️ Forces](./Forces.ipynb)\n",
     "- [⭐ Shapes](./Shapes.ipynb)\n",
     "- [🔮 3D](./3D.ipynb)\n",
-    "- [🥄 Widget Source](./WidgetSource.ipynb)"
+    "- [🥄 Widget Source](./WidgetSource.ipynb)\n",
+    "- [⚖️ Scales](./Scales.ipynb)"
    ]
   },
   {
diff --git a/js/tokens.ts b/js/tokens.ts
index a81ff5b0..dd8c0d19 100644
--- a/js/tokens.ts
+++ b/js/tokens.ts
@@ -79,9 +79,7 @@ export type TUpdateKind = void | number;
 export interface IBehave extends WidgetModel {
   rank: number;
   updateRequested: ISignal<IBehave, TUpdateKind>;
-  graphDataUpdateRequested: ISignal<IBehave, void>;
   extraColumns?: IExtraColumns;
-  updateGraphData?(graphData: GraphData): Promise<void>;
   // link
   getLinkColor?(options: ILinkBehaveOptions): string | null;
   getLinkCurvature?(options: ILinkBehaveOptions): number | null;
@@ -258,6 +256,8 @@ export enum ECoerce {
   numeric = 'number',
 }
 
+export type TCoercer = (value: any) => any;
+
 export interface IExtraColumns {
   nodes: string[];
   links: string[];
diff --git a/js/utils.ts b/js/utils.ts
index 6c1b624e..b9a7ddcf 100644
--- a/js/utils.ts
+++ b/js/utils.ts
@@ -2,7 +2,7 @@
  * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-import { DEBUG, ECoerce, EMOJI, FALSEY } from './tokens';
+import { DEBUG, ECoerce, EMOJI, FALSEY, TCoercer } from './tokens';
 
 export function noop(...args: any[]): null {
   return null;
@@ -48,7 +48,7 @@ export function coerceArray(value: string): any[] {
   return [];
 }
 
-export function getCoercer(coerce: ECoerce): (value: any) => any {
+export function getCoercer(coerce: ECoerce): TCoercer {
   switch (coerce) {
     case ECoerce.boolish:
       return coerceBoolish;
diff --git a/js/widgets/behaviors/base.ts b/js/widgets/behaviors/base.ts
index 6e935bf3..c497082a 100644
--- a/js/widgets/behaviors/base.ts
+++ b/js/widgets/behaviors/base.ts
@@ -13,6 +13,7 @@ import {
   ECoerce,
   EUpdate,
   IBehave,
+  TCoercer,
   TUpdateKind,
   WIDGET_DEFAULTS,
 } from '../../tokens';
@@ -20,7 +21,6 @@ import { functor, getCoercer, noop } from '../../utils';
 
 export class BehaviorModel extends WidgetModel implements IBehave {
   protected _updateRequested: Signal<IBehave, TUpdateKind>;
-  protected _graphDataUpdateRequested: Signal<IBehave, void>;
 
   defaults() {
     return { ...super.defaults(), ...WIDGET_DEFAULTS };
@@ -35,7 +35,6 @@ export class BehaviorModel extends WidgetModel implements IBehave {
     super.initialize(attributes, options);
     this.on('change:rank', this.onRankChange);
     this._updateRequested = new Signal(this);
-    this._graphDataUpdateRequested = new Signal(this);
   }
 
   onRankChange() {
@@ -45,10 +44,6 @@ export class BehaviorModel extends WidgetModel implements IBehave {
   get updateRequested(): ISignal<IBehave, TUpdateKind> {
     return this._updateRequested;
   }
-
-  get graphDataUpdateRequested(): ISignal<IBehave, void> {
-    return this._graphDataUpdateRequested;
-  }
 }
 
 export class FacetedModel extends BehaviorModel {
@@ -222,6 +217,13 @@ export class ColumnModel extends DynamicModel {
 
     const coercer = getCoercer(this.coerce);
 
+    const [_nodeHandler, _linkHandler] = await this._buildHandlers(value, coercer);
+
+    this._nodeHandler = _nodeHandler;
+    this._linkHandler = _linkHandler;
+  }
+
+  async _buildHandlers(value: any, coercer: TCoercer): Promise<Function[]> {
     function _nodeHandler(options: any) {
       return coercer(options.node ? options.node[value] : null);
     }
@@ -229,7 +231,7 @@ export class ColumnModel extends DynamicModel {
     function _linkHandler(options: any) {
       return coercer(options.link ? options.link[value] : null);
     }
-    this._nodeHandler = _nodeHandler;
-    this._linkHandler = _linkHandler;
+
+    return [_nodeHandler, _linkHandler];
   }
 }
diff --git a/js/widgets/behaviors/index.ts b/js/widgets/behaviors/index.ts
index 2dcc5a95..fbe4e753 100644
--- a/js/widgets/behaviors/index.ts
+++ b/js/widgets/behaviors/index.ts
@@ -16,3 +16,4 @@ export * from './node-selection';
 export * from './node-shape';
 export * from './node-tooltip';
 export * from './shapes';
+export * from './scales';
diff --git a/js/widgets/behaviors/link-selection.ts b/js/widgets/behaviors/link-selection.ts
index a41906d1..52dfae92 100644
--- a/js/widgets/behaviors/link-selection.ts
+++ b/js/widgets/behaviors/link-selection.ts
@@ -2,8 +2,6 @@
  * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-import { GraphData } from 'force-graph';
-
 import { IBackboneModelOptions } from '@jupyter-widgets/base';
 
 import {
@@ -11,7 +9,6 @@ import {
   DEFAULT_CURVATURES,
   DEFAULT_LINE_DASHES,
   DEFAULT_WIDTHS,
-  EUpdate,
   IBehave,
   IExtraColumns,
   ILinkBehaveOptions,
@@ -50,22 +47,7 @@ export class LinkSelectionModel extends BehaviorModel implements IBehave {
   }
 
   onValueChange(change?: any) {
-    this._updateRequested.emit(EUpdate.Render);
-    if (this.columnName) {
-      this._graphDataUpdateRequested.emit(void 0);
-    }
-  }
-
-  async updateGraphData(graphData: GraphData): Promise<void> {
-    const { selected, columnName } = this;
-    if (!columnName) {
-      return;
-    }
-    const { links } = graphData;
-    const linkCount = links.length;
-    for (let i = 0; i < linkCount; i++) {
-      links[i][columnName] = selected.has(i);
-    }
+    this._updateRequested.emit(void 0);
   }
 
   get selected(): TSelectedSet {
diff --git a/js/widgets/behaviors/node-selection.ts b/js/widgets/behaviors/node-selection.ts
index 506832b7..042e63b2 100644
--- a/js/widgets/behaviors/node-selection.ts
+++ b/js/widgets/behaviors/node-selection.ts
@@ -2,13 +2,10 @@
  * Copyright (c) 2023 ipyforcegraph contributors.
  * Distributed under the terms of the Modified BSD License.
  */
-import { GraphData } from 'force-graph';
-
 import { IBackboneModelOptions } from '@jupyter-widgets/base';
 
 import {
   DEFAULT_COLORS,
-  EUpdate,
   IBehave,
   IExtraColumns,
   INodeBehaveOptions,
@@ -44,22 +41,7 @@ export class NodeSelectionModel extends BehaviorModel implements IBehave {
   }
 
   onValueChange(change?: any) {
-    this._updateRequested.emit(EUpdate.Render);
-    if (this.columnName) {
-      this._graphDataUpdateRequested.emit(void 0);
-    }
-  }
-
-  async updateGraphData(graphData: GraphData): Promise<void> {
-    const { selected, columnName } = this;
-    if (!columnName) {
-      return;
-    }
-    const { nodes } = graphData;
-    const nodeCount = nodes.length;
-    for (let i = 0; i < nodeCount; i++) {
-      nodes[i][columnName] = selected.has(i);
-    }
+    this._updateRequested.emit(void 0);
   }
 
   get selected(): TSelectedSet {
diff --git a/js/widgets/behaviors/scales.ts b/js/widgets/behaviors/scales.ts
new file mode 100644
index 00000000..32d322e1
--- /dev/null
+++ b/js/widgets/behaviors/scales.ts
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2023 ipyforcegraph contributors.
+ * Distributed under the terms of the Modified BSD License.
+ */
+import { IBackboneModelOptions } from '@jupyter-widgets/base';
+
+import { TCoercer } from '../../tokens';
+import { noop } from '../../utils';
+
+import { ColumnModel } from './base';
+
+const noopHanlders = [noop, noop];
+
+export class ContinuousColorModel extends ColumnModel {
+  initialize(attributes: Backbone.ObjectHash, options: IBackboneModelOptions) {
+    super.initialize(attributes, options);
+    this.on('change:scheme change:domain', this.valueChanged, this);
+  }
+
+  async _buildHandlers(value: any, coercer: TCoercer): Promise<Function[]> {
+    let { scheme, domain } = this;
+
+    const min = domain[0];
+    const max = domain.slice(-1)[0];
+
+    const d3sc = await import('d3-scale-chromatic');
+    const interpolate = d3sc[`interpolate${scheme}`];
+
+    if (!interpolate) {
+      console.warn(`${scheme} cannot be interpolated`);
+      return noopHanlders;
+    }
+
+    const base = max - min;
+
+    function _nodeHandler(options: any) {
+      const v = coercer(options.node ? options.node[value] : null);
+      return v == null ? v : interpolate((v - min) / base);
+    }
+
+    function _linkHandler(options: any) {
+      const v = coercer(options.link ? options.link[value] : null);
+      return v == null ? v : interpolate((v - min) / base);
+    }
+
+    return [_nodeHandler, _linkHandler];
+  }
+
+  get scheme(): string {
+    return this.get('scheme');
+  }
+
+  get domain(): number[] {
+    return this.get('domain') || [0, 1];
+  }
+}
+
+export class OrdinalColorModel extends ColumnModel {
+  initialize(attributes: Backbone.ObjectHash, options: IBackboneModelOptions) {
+    super.initialize(attributes, options);
+    this.on(
+      'change:scheme change:domain change:range change:sub_scheme',
+      this.valueChanged,
+      this
+    );
+  }
+
+  async _buildHandlers(value: any, coercer: TCoercer): Promise<Function[]> {
+    let { scheme, range, domain } = this;
+    const [d3sc, d3s] = await Promise.all([
+      import('d3-scale-chromatic'),
+      import('d3-scale'),
+    ]);
+
+    if (scheme) {
+      const schemeRange = d3sc[`scheme${scheme}`];
+      if (schemeRange) {
+        range = schemeRange;
+      }
+    }
+
+    const scale = d3s.scaleOrdinal(range).domain(domain);
+
+    function _nodeHandler(options: any) {
+      const v = coercer(options.node ? options.node[value] : null);
+      return v == null ? v : scale(v);
+    }
+
+    function _linkHandler(options: any) {
+      const v = coercer(options.link ? options.link[value] : null);
+      return v == null ? v : scale(v);
+    }
+
+    return [_nodeHandler, _linkHandler];
+  }
+
+  get scheme(): string {
+    return this.get('scheme');
+  }
+
+  get domain(): any[] {
+    return this.get('domain') || [0, 1];
+  }
+
+  get range(): string[] {
+    return this.get('range') || [];
+  }
+}
diff --git a/js/widgets/display/2d.ts b/js/widgets/display/2d.ts
index b255a3a9..66ac7e94 100644
--- a/js/widgets/display/2d.ts
+++ b/js/widgets/display/2d.ts
@@ -470,13 +470,6 @@ export class ForceGraphView<T = ForceGraphGenericInstance<ForceGraphInstance>>
     }
   }
 
-  protected async onGraphDataUpdateRequested(behavior: IBehave) {
-    const graph = this.graph as ForceGraphInstance;
-    if (graph && behavior.updateGraphData) {
-      await behavior.updateGraphData(graph.graphData());
-    }
-  }
-
   protected async postUpdate(caller?: any, kind?: TUpdateKind): Promise<void> {
     await this.displayed;
     await this.rendered;
@@ -693,7 +686,6 @@ export class ForceGraphView<T = ForceGraphGenericInstance<ForceGraphInstance>>
 
     for (const behavior of behaviors) {
       behavior.updateRequested.connect(this.postUpdate, this);
-      behavior.graphDataUpdateRequested.connect(this.onGraphDataUpdateRequested, this);
     }
 
     await this.postUpdate();
diff --git a/package.json b/package.json
index daeb2eb6..73296f25 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,7 @@
     "webpack": "^5.76.0"
   },
   "dependencies": {
-    "@bokuweb/zstd-wasm": "~0.0.19",
+    "@bokuweb/zstd-wasm": "~0.0.20",
     "@jupyter-widgets/base": "^6.0.2",
     "@jupyter-widgets/controls": "^5.0.3",
     "@jupyter-widgets/jupyterlab-manager": "^5.0.5",
@@ -50,9 +50,11 @@
     "buffer": "^6.0.3",
     "d3-force-3d": "~3.0.5",
     "d3-force-cluster-3d": "~1.1.1",
-    "force-graph": "~1.43.0",
+    "d3-scale": "^4.0.2",
+    "d3-scale-chromatic": "^3.0.0",
+    "force-graph": "~1.43.1",
     "nunjucks": "^3.2.3",
-    "three-spritetext": "~1.8.0"
+    "three-spritetext": "~1.8.1"
   },
   "devDependencies": {
     "@jupyterlab/application": "3",
@@ -61,11 +63,13 @@
     "@jupyterlab/theme-light-extension": "3",
     "@trivago/prettier-plugin-sort-imports": "^4.0.0",
     "@types/d3-force": "^3.0.4",
+    "@types/d3-scale": "^4.0.3",
+    "@types/d3-scale-chromatic": "^3.0.0",
     "@types/nunjucks": "^3.2.1",
     "@types/three": "^0.148.0",
     "file-loader": "^6.2.0",
     "npm-run-all": "^4.1.5",
-    "prettier": "^2.8.7",
+    "prettier": "^2.8.8",
     "prettier-package-json": "^2.8.0",
     "prettier-plugin-sort-json": "^1.0.0",
     "rimraf": "^4.4.1",
diff --git a/src/ipyforcegraph/behaviors/forces.py b/src/ipyforcegraph/behaviors/forces.py
index 9af78e36..6ae061bd 100644
--- a/src/ipyforcegraph/behaviors/forces.py
+++ b/src/ipyforcegraph/behaviors/forces.py
@@ -15,7 +15,7 @@
 import ipywidgets as W
 import traitlets as T
 
-from ..trait_utils import JSON_TYPES, coerce
+from ..trait_utils import JSON_TYPES, coerce, validate_enum
 from ._base import (
     BaseD3Force,
     Behavior,
@@ -450,11 +450,4 @@ def _validate_scale_bools(self, proposal: T.Bunch) -> Any:
 
     @T.validate("mode")
     def _validate_enum(self, proposal: T.Bunch) -> Any:
-        mode = proposal.value
-        if isinstance(mode, DAG.Mode):
-            return mode.value
-
-        if any(mode == m.value for m in DAG.Mode):
-            return mode
-
-        raise T.TraitError(f"{mode} is not one of {[*DAG.Mode]}")
+        return validate_enum(proposal, DAG.Mode)
diff --git a/src/ipyforcegraph/behaviors/scales.py b/src/ipyforcegraph/behaviors/scales.py
new file mode 100644
index 00000000..e7523e6f
--- /dev/null
+++ b/src/ipyforcegraph/behaviors/scales.py
@@ -0,0 +1,119 @@
+"""Column-wise scales for ``ipyforcegraph``.
+
+Some documentation provided by:
+- `d3-scale-chromatic <https://github.com/d3/d3-scale-chromatic>`_
+"""
+
+# Copyright (c) 2023 ipyforcegraph contributors.
+# Distributed under the terms of the Modified BSD License.
+
+import enum
+from typing import Any, Tuple
+
+import ipywidgets as W
+import traitlets as T
+
+from ..trait_utils import validate_enum
+from ._base import Column
+
+
+class ContinuousColor(Column):
+    """A column which will interpolate a numeric column on a color scale."""
+
+    class Scheme(enum.Enum):
+        """Continuous color schemes exported by ``d3-scale-chromatic``"""
+
+        blues = "Blues"
+        brbg = "BrBG"
+        bugn = "BuGn"
+        bupu = "BuPu"
+        cividis = "Cividis"
+        cool = "Cool"
+        cubehelixdefault = "CubehelixDefault"
+        gnbu = "GnBu"
+        greens = "Greens"
+        greys = "Greys"
+        inferno = "Inferno"
+        magma = "Magma"
+        oranges = "Oranges"
+        orrd = "OrRd"
+        piyg = "PiYG"
+        plasma = "Plasma"
+        prgn = "PRGn"
+        pubu = "PuBu"
+        pubugn = "PuBuGn"
+        puor = "PuOr"
+        purd = "PuRd"
+        purples = "Purples"
+        rainbow = "Rainbow"
+        rdbu = "RdBu"
+        rdgy = "RdGy"
+        rdpu = "RdPu"
+        rdylbu = "RdYlBu"
+        rdylgn = "RdYlGn"
+        reds = "Reds"
+        sinebow = "Sinebow"
+        spectral = "Spectral"
+        turbo = "Turbo"
+        viridis = "Viridis"
+        warm = "Warm"
+        ylgn = "YlGn"
+        ylgnbu = "YlGnBu"
+        ylorbr = "YlOrBr"
+        ylorrd = "YlOrRd"
+
+    _model_name: str = T.Unicode("ContinuousColorModel").tag(sync=True)
+
+    scheme: str = T.Enum(
+        values=[*[m.value for m in Scheme], *Scheme],
+        help="name of a continuous ``d3-scale-chromatic`` scheme",
+        allow_none=True,
+    ).tag(sync=True)
+
+    domain: Tuple[float, float] = W.TypedTuple(
+        (0.0, 1.0),
+        help=("the ``[min, max]`` to map to the scale's colors"),
+    ).tag(sync=True)
+
+    @T.validate("scheme")
+    def _validate_scheme(self, proposal: T.Bunch) -> Any:
+        return validate_enum(proposal, ContinuousColor.Scheme)
+
+
+class OrdinalColor(Column):
+    """A column which will encode a column on an discrete color scale."""
+
+    class Scheme(enum.Enum):
+        """Ordinal color schemes exported by ``d3-scale-chromatic``"""
+
+        accent = "Accent"
+        category10 = "Category10"
+        dark2 = "Dark2"
+        paired = "Paired"
+        pastel1 = "Pastel1"
+        pastel2 = "Pastel2"
+        set1 = "Set1"
+        set2 = "Set2"
+        set3 = "Set3"
+        tableau10 = "Tableau10"
+
+    _model_name: str = T.Unicode("OrdinalColorModel").tag(sync=True)
+
+    scheme: str = T.Enum(
+        values=[*[m.value for m in Scheme], *Scheme],
+        help="name of an ordinal ``d3-scale-chromatic`` scheme",
+        allow_none=True,
+    ).tag(sync=True)
+
+    domain: Tuple[Any] = T.Tuple(
+        (0.0, 1.0),
+        help=("values mapped to ordinal colors in the range"),
+    ).tag(sync=True)
+
+    range: Tuple[str] = W.TypedTuple(
+        T.Unicode(), help="the colors available in a scheme (overloaded by ``scheme``)"
+    ).tag(sync=True)
+
+    @T.validate("scheme")
+    def _validate_scheme(self, proposal: T.Bunch) -> Any:
+        return validate_enum(proposal, OrdinalColor.Scheme)
diff --git a/src/ipyforcegraph/trait_utils.py b/src/ipyforcegraph/trait_utils.py
index 15091f47..ea811a87 100644
--- a/src/ipyforcegraph/trait_utils.py
+++ b/src/ipyforcegraph/trait_utils.py
@@ -3,7 +3,8 @@
 # Copyright (c) 2023 ipyforcegraph contributors.
 # Distributed under the terms of the Modified BSD License.
 
-from typing import Any, Tuple
+import enum
+from typing import Any, Tuple, Type
 
 import traitlets as T
 
@@ -35,3 +36,15 @@ def coerce(proposal: T.Bunch, json_type: str) -> Any:
         value.coerce = json_type
 
     return value
+
+
+def validate_enum(proposal: T.Bunch, of_enum: Type[enum.Enum]) -> Any:
+    """Validate a proposal against an enum (or its names)."""
+    value = proposal.value
+    if isinstance(value, of_enum):
+        return value.value
+
+    if any(value == m.value for m in of_enum):
+        return value
+
+    raise T.TraitError(f"""'{value}' is not one of {", ".join([*of_enum])}""")
diff --git a/yarn.lock b/yarn.lock
index cf07d1c2..8932689c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -169,10 +169,10 @@
     classnames "^2.2"
     tslib "~2.3.1"
 
-"@bokuweb/zstd-wasm@~0.0.19":
-  version "0.0.19"
-  resolved "https://registry.npmjs.org/@bokuweb/zstd-wasm/-/zstd-wasm-0.0.19.tgz#51b267db13f98850eca1d277eb32330a1e0044df"
-  integrity sha512-Y17cCvp1Fc70j3h3NP0QPlOblWwBwWQyDDAdQjxgJgc4/H7z4CsFLc9SRfdPX7owiMVJGlmEnPmV9tMLM8jsKw==
+"@bokuweb/zstd-wasm@~0.0.20":
+  version "0.0.20"
+  resolved "https://registry.npmjs.org/@bokuweb/zstd-wasm/-/zstd-wasm-0.0.20.tgz#fab3cc3854ebc2a6c4f1921d5bb518e28f674a0f"
+  integrity sha512-l/48EbQXz8FobRP6/rs5Voca+mrgtCldDF787sTekiHHP6yUW5kvjpDU7xSNI6pjrXjbDVyUZq5HN8kkevu3Og==
 
 "@discoveryjs/json-ext@^0.5.0":
   version "0.5.7"
@@ -1020,6 +1020,11 @@
   resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-18.6.4.tgz#40a3d0a93647124872dec8e0fd1bd5926695b6ca"
   integrity sha512-lB9lMjuqjtuJrx7/kOkqQBtllspPIN+96OvTCeJ2j5FEzinoAXTdAMFnDAQT1KVPRlnYfBrqxtqP66vDM40xxQ==
 
+"@tweenjs/tween.js@19":
+  version "19.0.0"
+  resolved "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-19.0.0.tgz#93d3169f665ddc184c3b1b7a1910bf7df3dfb5da"
+  integrity sha512-QVbvSlnP7FcjKr1edg460BbUlpdGzmIOfvpsvHCj3JPIVZ9S9KeQLk9mB24VlDzPIl/a/ehAZPE95xFsmqm+pQ==
+
 "@types/backbone@1.4.14":
   version "1.4.14"
   resolved "https://registry.npmjs.org/@types/backbone/-/backbone-1.4.14.tgz#4b71f0c25d89cfa9a10b18042f0b03d35a53364c"
@@ -1033,6 +1038,23 @@
   resolved "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.4.tgz#2d50bd2b695f709797e1745644f6bc123e6e5f5a"
   integrity sha512-q7xbVLrWcXvSBBEoadowIUJ7sRpS1yvgMWnzHJggFy5cUZBq2HZL5k/pBSm0GdYWS1vs5/EDwMjSKF55PDY4Aw==
 
+"@types/d3-scale-chromatic@^3.0.0":
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#103124777e8cdec85b20b51fd3397c682ee1e954"
+  integrity sha512-dsoJGEIShosKVRBZB0Vo3C8nqSDqVGujJU6tPznsBJxNJNwMF8utmS83nvCBKQYPpjCzaaHcrf66iTRpZosLPw==
+
+"@types/d3-scale@^4.0.3":
+  version "4.0.3"
+  resolved "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz#7a5780e934e52b6f63ad9c24b105e33dd58102b5"
+  integrity sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==
+  dependencies:
+    "@types/d3-time" "*"
+
+"@types/d3-time@*":
+  version "3.0.0"
+  resolved "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz#e1ac0f3e9e195135361fa1a1d62f795d87e6e819"
+  integrity sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==
+
 "@types/dom4@^2.0.1":
   version "2.0.2"
   resolved "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.2.tgz#6495303f049689ce936ed328a3e5ede9c51408ee"
@@ -1784,7 +1806,7 @@ d3-octree@1:
   resolved "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz#6dca3e8be2b393c9a9d514dabbd80a92deef1a4f"
   integrity sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==
 
-"d3-scale-chromatic@1 - 3":
+"d3-scale-chromatic@1 - 3", d3-scale-chromatic@^3.0.0:
   version "3.0.0"
   resolved "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.0.0.tgz#15b4ceb8ca2bb0dcb6d1a641ee03d59c3b62376a"
   integrity sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==
@@ -1792,7 +1814,7 @@ d3-octree@1:
     d3-color "1 - 3"
     d3-interpolate "1 - 3"
 
-"d3-scale@1 - 4":
+"d3-scale@1 - 4", d3-scale@^4.0.2:
   version "4.0.2"
   resolved "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396"
   integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==
@@ -2182,12 +2204,12 @@ for-each@^0.3.3:
   dependencies:
     is-callable "^1.1.3"
 
-force-graph@~1.43.0:
-  version "1.43.0"
-  resolved "https://registry.npmjs.org/force-graph/-/force-graph-1.43.0.tgz#b41754a6a0693b38bf4f831c64bf9069a068de85"
-  integrity sha512-nOG818GgID0Boi5OJyjlHuhV5EO4cEaxpXCN+eXqBiG2Mc+8TtqRZrA347grWmeliMdtfldMqYAb/ZKs26qf+w==
+force-graph@~1.43.1:
+  version "1.43.1"
+  resolved "https://registry.npmjs.org/force-graph/-/force-graph-1.43.1.tgz#40ab780f92e6be7567b82be300bd5c328b50f00d"
+  integrity sha512-JOrmhMYr3uF6zzCXTauEo0KIiSp9OB2fAYYXkOGs6z0GQNSLIpcjCY3lhod4kAbkQCOup+u8JE9mmw7ojQaxTQ==
   dependencies:
-    "@tweenjs/tween.js" "18"
+    "@tweenjs/tween.js" "19"
     accessor-fn "1"
     bezier-js "3 - 6"
     canvas-color-tracker "1"
@@ -2199,8 +2221,8 @@ force-graph@~1.43.0:
     d3-selection "2 - 3"
     d3-zoom "2 - 3"
     index-array-by "1"
-    kapsule "^1.13"
-    lodash.throttle "4"
+    kapsule "^1.14"
+    lodash-es "4"
 
 free-style@3.1.0:
   version "3.1.0"
@@ -2712,7 +2734,7 @@ jsonpointer@^5.0.0:
   resolved "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559"
   integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
 
-kapsule@^1.13, kapsule@^1.14:
+kapsule@^1.14:
   version "1.14.1"
   resolved "https://registry.npmjs.org/kapsule/-/kapsule-1.14.1.tgz#344a0a7b3e48ee0942ad58ee97daac12433bc1ef"
   integrity sha512-zA9LbOApzkDtulUYNp5R2RVXX1mS6tIoPlhsr8bVQPsGvTQHXnF8W3n0mC//lMciu/NNvtqv+lXUahDn9P6Y0Q==
@@ -2866,6 +2888,11 @@ locate-path@^5.0.0:
   dependencies:
     p-locate "^4.1.0"
 
+lodash-es@4:
+  version "4.17.21"
+  resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
 lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -2876,11 +2903,6 @@ lodash.escape@^4.0.1:
   resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98"
   integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==
 
-lodash.throttle@4:
-  version "4.1.1"
-  resolved "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4"
-  integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==
-
 lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0:
   version "4.17.21"
   resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
@@ -3406,10 +3428,10 @@ prettier-plugin-sort-json@^1.0.0:
   dependencies:
     "@types/prettier" "^2.7.2"
 
-prettier@^2.8.3, prettier@^2.8.7:
-  version "2.8.7"
-  resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.7.tgz#bb79fc8729308549d28fe3a98fce73d2c0656450"
-  integrity sha512-yPngTo3aXUUmyuTjeTUT75txrf+aMh9FiD7q9ZE/i6r0bPb22g4FsE6Y338PQX1bmfy08i9QQCB7/rcUAVntfw==
+prettier@^2.8.3, prettier@^2.8.8:
+  version "2.8.8"
+  resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
+  integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
 
 process@^0.11.10:
   version "0.11.10"
@@ -4002,10 +4024,10 @@ three-render-objects@^1.28:
     kapsule "^1.14"
     polished "4"
 
-three-spritetext@~1.8.0:
-  version "1.8.0"
-  resolved "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.8.0.tgz#b7a2c427d5ffe74f7a529051ee9ff5047aecfde2"
-  integrity sha512-ehiATMfR1guCk+knjCxDWp2zikxRbxQaKXJyjXwuZKqjIbKtsCh7BQ00JHaESjzaXXhG5LJV7rXTJ78M/EYWyQ==
+three-spritetext@~1.8.1:
+  version "1.8.1"
+  resolved "https://registry.npmjs.org/three-spritetext/-/three-spritetext-1.8.1.tgz#e554230b6f80c75251e0275b8408b8cf2dc2b101"
+  integrity sha512-pohv5CcdeUtAPLi9KhG0kcDLj3gmzdIFK/QlgsTJe+U07oQFSj+K0DLPQKbNDPWAK+7YzhulkRcjWdVIQ5F7nw==
 
 "three@>=0.118 <1":
   version "0.150.1"


Test patch:
diff --git a/.github/locks/linux-64_test_lab3.5_py3.11.conda.lock b/.github/locks/linux-64_test_lab3.5_py3.11.conda.lock
index 62b4e311..9f7e5e99 100644
--- a/.github/locks/linux-64_test_lab3.5_py3.11.conda.lock
+++ b/.github/locks/linux-64_test_lab3.5_py3.11.conda.lock
@@ -36,7 +36,7 @@
 
 @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.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
@@ -47,7 +47,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.2.0-h65d4601_19.tar.b
 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d
 https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535
 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54
-https://conda.anaconda.org/conda-forge/linux-64/firefox-102.10.0esr-hcb278e6_0.conda#057cc9aca5cdf3ed6d4247a1d98e5568
+https://conda.anaconda.org/conda-forge/linux-64/firefox-102.11.0esr-h59595ed_0.conda#b8a18b5550c271147a9d048368db4093
 https://conda.anaconda.org/conda-forge/linux-64/geckodriver-0.33.0-hd2f7af9_0.conda#83664049f2b276cc23bd67d41eb9a4ee
 https://conda.anaconda.org/conda-forge/linux-64/icu-72.1-hcb278e6_0.conda#7c8d20d847bb45f56bd941578fcfa146
 https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd
@@ -63,7 +63,7 @@ https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-hd590300_3.conda#8
 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/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b
-https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.4-hfdac1af_0.conda#241845899caff54ac1d2b3102ad988cf
 https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.19.2-h32600fe_2.conda#326f46f36d15c44cff5f81d505cb717f
 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4
@@ -74,10 +74,10 @@ https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openb
 https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.37-h873f0b0_0.tar.bz2#ed0d77d947ddeb974892de8df7224d12
 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.3-h2755cc3_0_cpython.conda#37005ea5f68df6a8a381b70cf4d4a160
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -184,7 +184,7 @@ https://conda.anaconda.org/conda-forge/noarch/doit-0.36.0-pyhd8ed1ab_0.tar.bz2#f
 https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.6.0-hd8ed1ab_0.conda#3cbc9615f10a3d471532b83e4250b971
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_terminals-0.4.4-pyhd8ed1ab_1.conda#7c0965e1d4a0ee1529e8eaa03a78a5b3
-https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_0.conda#de0bcfeb3c829f630399dc6b5ab829e1
+https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_1.conda#37f841a3140999c4735f7d8091072bea
 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.5.0-pyhd8ed1ab_0.conda#6c36f1c42dd0069b7f23acc74f19be46
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.3.1-pyhd8ed1ab_0.conda#547c7de697ec99b494a28ddde185b5a4
 https://conda.anaconda.org/conda-forge/noarch/rich-13.3.5-pyhd8ed1ab_0.conda#2e40a02ad28e34f26cee2a72042843db
@@ -216,18 +216,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyh41d4057_0.conda#e8563c13eee80a5f1c7bdfc2a1b20077
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.3-pyh210e3f2_0.conda#8c1f6bf32a6ca81232c4853d4165ca67
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/linux-64_test_lab3.5_py3.8.conda.lock b/.github/locks/linux-64_test_lab3.5_py3.8.conda.lock
index 36a61d6d..290170c5 100644
--- a/.github/locks/linux-64_test_lab3.5_py3.8.conda.lock
+++ b/.github/locks/linux-64_test_lab3.5_py3.8.conda.lock
@@ -37,7 +37,7 @@
 
 @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.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
@@ -47,7 +47,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.2.0-h65d4601_19.tar.b
 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d
 https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535
 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54
-https://conda.anaconda.org/conda-forge/linux-64/firefox-102.10.0esr-hcb278e6_0.conda#057cc9aca5cdf3ed6d4247a1d98e5568
+https://conda.anaconda.org/conda-forge/linux-64/firefox-102.11.0esr-h59595ed_0.conda#b8a18b5550c271147a9d048368db4093
 https://conda.anaconda.org/conda-forge/linux-64/geckodriver-0.33.0-hd2f7af9_0.conda#83664049f2b276cc23bd67d41eb9a4ee
 https://conda.anaconda.org/conda-forge/linux-64/icu-72.1-hcb278e6_0.conda#7c8d20d847bb45f56bd941578fcfa146
 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3
@@ -62,7 +62,7 @@ https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-hd590300_3.conda#8
 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/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b
-https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.4-hfdac1af_0.conda#241845899caff54ac1d2b3102ad988cf
 https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.19.2-h32600fe_2.conda#326f46f36d15c44cff5f81d505cb717f
 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4
@@ -73,10 +73,10 @@ https://conda.anaconda.org/conda-forge/linux-64/liblapack-3.9.0-16_linux64_openb
 https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.37-h873f0b0_0.tar.bz2#ed0d77d947ddeb974892de8df7224d12
 https://conda.anaconda.org/conda-forge/linux-64/python-3.8.16-he550d4f_1_cpython.conda#9de84cccfbc5f8350a3667bb6ef6fc30
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -214,18 +214,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyh41d4057_0.conda#acebfd89278ecac2a67b60b657e00d5c
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.3-pyh210e3f2_0.conda#8c1f6bf32a6ca81232c4853d4165ca67
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/linux-64_test_lab3.6_py3.11.conda.lock b/.github/locks/linux-64_test_lab3.6_py3.11.conda.lock
index 4681c91c..42e015b3 100644
--- a/.github/locks/linux-64_test_lab3.6_py3.11.conda.lock
+++ b/.github/locks/linux-64_test_lab3.6_py3.11.conda.lock
@@ -34,7 +34,7 @@
 
 @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.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
@@ -45,7 +45,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.2.0-h65d4601_19.tar.b
 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d
 https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535
 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54
-https://conda.anaconda.org/conda-forge/linux-64/firefox-102.10.0esr-hcb278e6_0.conda#057cc9aca5cdf3ed6d4247a1d98e5568
+https://conda.anaconda.org/conda-forge/linux-64/firefox-102.11.0esr-h59595ed_0.conda#b8a18b5550c271147a9d048368db4093
 https://conda.anaconda.org/conda-forge/linux-64/geckodriver-0.33.0-hd2f7af9_0.conda#83664049f2b276cc23bd67d41eb9a4ee
 https://conda.anaconda.org/conda-forge/linux-64/icu-72.1-hcb278e6_0.conda#7c8d20d847bb45f56bd941578fcfa146
 https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.5.0-hcb278e6_1.conda#6305a3dd2752c76335295da4e581f2fd
@@ -61,7 +61,7 @@ https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-hd590300_3.conda#8
 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/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b
-https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.4-hfdac1af_0.conda#241845899caff54ac1d2b3102ad988cf
 https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.19.2-h32600fe_2.conda#326f46f36d15c44cff5f81d505cb717f
 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4
@@ -73,10 +73,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.37-h873f0b0_0.tar.bz
 https://conda.anaconda.org/conda-forge/linux-64/python-3.11.3-h2755cc3_0_cpython.conda#37005ea5f68df6a8a381b70cf4d4a160
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -105,7 +105,7 @@ https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.3-py311h64a7726_0.conda#f1d507e1a5f1151845f7818ceb02ba9f
-https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.11-py311h34b1e23_0.conda#40b9902e930c9ec2a7a761aea109704d
+https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.12-py311h34b1e23_0.conda#38293fbb4e657a3cc911afa3f45b018e
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -186,7 +186,7 @@ https://conda.anaconda.org/conda-forge/noarch/doit-0.36.0-pyhd8ed1ab_0.tar.bz2#f
 https://conda.anaconda.org/conda-forge/noarch/importlib_metadata-6.6.0-hd8ed1ab_0.conda#3cbc9615f10a3d471532b83e4250b971
 https://conda.anaconda.org/conda-forge/noarch/jsonschema-4.17.3-pyhd8ed1ab_0.conda#723268a468177cd44568eb8f794e0d80
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_terminals-0.4.4-pyhd8ed1ab_1.conda#7c0965e1d4a0ee1529e8eaa03a78a5b3
-https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_0.conda#de0bcfeb3c829f630399dc6b5ab829e1
+https://conda.anaconda.org/conda-forge/linux-64/pandas-2.0.1-py311h320fe9a_1.conda#37f841a3140999c4735f7d8091072bea
 https://conda.anaconda.org/conda-forge/noarch/platformdirs-3.5.0-pyhd8ed1ab_0.conda#6c36f1c42dd0069b7f23acc74f19be46
 https://conda.anaconda.org/conda-forge/noarch/pytest-7.3.1-pyhd8ed1ab_0.conda#547c7de697ec99b494a28ddde185b5a4
 https://conda.anaconda.org/conda-forge/noarch/rich-13.3.5-pyhd8ed1ab_0.conda#2e40a02ad28e34f26cee2a72042843db
@@ -220,19 +220,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyh41d4057_0.conda#e8563c13eee80a5f1c7bdfc2a1b20077
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh210e3f2_0.conda#1b463a5f4b7c83f509f6a1168a6ef554
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh210e3f2_0.conda#a9d13f9aee96fd4650928ac0302b0bf8
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/linux-64_test_lab3.6_py3.8.conda.lock b/.github/locks/linux-64_test_lab3.6_py3.8.conda.lock
index ab39bde5..2927437e 100644
--- a/.github/locks/linux-64_test_lab3.6_py3.8.conda.lock
+++ b/.github/locks/linux-64_test_lab3.6_py3.8.conda.lock
@@ -35,7 +35,7 @@
 
 @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.12.7-ha878542_0.conda#ff9f73d45c4a07d6f424495288a26080
+https://conda.anaconda.org/conda-forge/linux-64/ca-certificates-2023.5.7-hbcca054_0.conda#f5c65075fc34438d5b456c7f3f5ab695
 https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.40-h41732ed_0.conda#7aca3059a1729aa76c597603f10b0dd3
 https://conda.anaconda.org/conda-forge/linux-64/libgfortran5-12.2.0-h337968e_19.tar.bz2#164b4b1acaedc47ee7e658ae6b308ca3
 https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-ng-12.2.0-h46fd767_19.tar.bz2#1030b1f38c129f2634eae026f704fe60
@@ -45,7 +45,7 @@ https://conda.anaconda.org/conda-forge/linux-64/libgomp-12.2.0-h65d4601_19.tar.b
 https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-2_gnu.tar.bz2#73aaf86a425cc6e73fcf236a5a46396d
 https://conda.anaconda.org/conda-forge/linux-64/libgcc-ng-12.2.0-h65d4601_19.tar.bz2#e4c94f80aef025c17ab0828cd85ef535
 https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-h7f98852_4.tar.bz2#a1fd65c7ccbf10880423d82bca54eb54
-https://conda.anaconda.org/conda-forge/linux-64/firefox-102.10.0esr-hcb278e6_0.conda#057cc9aca5cdf3ed6d4247a1d98e5568
+https://conda.anaconda.org/conda-forge/linux-64/firefox-102.11.0esr-h59595ed_0.conda#b8a18b5550c271147a9d048368db4093
 https://conda.anaconda.org/conda-forge/linux-64/geckodriver-0.33.0-hd2f7af9_0.conda#83664049f2b276cc23bd67d41eb9a4ee
 https://conda.anaconda.org/conda-forge/linux-64/icu-72.1-hcb278e6_0.conda#7c8d20d847bb45f56bd941578fcfa146
 https://conda.anaconda.org/conda-forge/linux-64/libffi-3.4.2-h7f98852_5.tar.bz2#d645c6d2ac96843a2bfaccd2d62b3ac3
@@ -60,7 +60,7 @@ https://conda.anaconda.org/conda-forge/linux-64/openssl-3.1.0-hd590300_3.conda#8
 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/libblas-3.9.0-16_linux64_openblas.tar.bz2#d9b7a8639171f6c6fa0a983edabcfe2b
-https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.40.0-h753d276_1.conda#32565f92ca100184c67509d1d91c858a
+https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.41.2-h2797004_1.conda#1d002bf709048f8021c32abfd0e0d395
 https://conda.anaconda.org/conda-forge/linux-64/libxml2-2.10.4-hfdac1af_0.conda#241845899caff54ac1d2b3102ad988cf
 https://conda.anaconda.org/conda-forge/linux-64/pandoc-2.19.2-h32600fe_2.conda#326f46f36d15c44cff5f81d505cb717f
 https://conda.anaconda.org/conda-forge/linux-64/readline-8.2-h8228510_1.conda#47d31b792659ce70f470b5c82fdfb7a4
@@ -72,10 +72,10 @@ https://conda.anaconda.org/conda-forge/linux-64/libxslt-1.1.37-h873f0b0_0.tar.bz
 https://conda.anaconda.org/conda-forge/linux-64/python-3.8.16-he550d4f_1_cpython.conda#9de84cccfbc5f8350a3667bb6ef6fc30
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -104,7 +104,7 @@ https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
 https://conda.anaconda.org/conda-forge/linux-64/numpy-1.24.3-py38h59b608b_0.conda#5836e4ab0399136ede58446a4776b2ff
-https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.11-py38h0488081_0.conda#cf1fa3394e06727a2d2762b8b8c2aad1
+https://conda.anaconda.org/conda-forge/linux-64/orjson-3.8.12-py38h0488081_0.conda#cbe1d6c8215c663bc8f1ed45ef02a44b
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -218,19 +218,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyh41d4057_0.conda#acebfd89278ecac2a67b60b657e00d5c
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh210e3f2_0.conda#1b463a5f4b7c83f509f6a1168a6ef554
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh210e3f2_0.conda#a9d13f9aee96fd4650928ac0302b0bf8
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/osx-64_test_lab3.5_py3.11.conda.lock b/.github/locks/osx-64_test_lab3.5_py3.11.conda.lock
index a666f99a..09fcf84a 100644
--- a/.github/locks/osx-64_test_lab3.5_py3.11.conda.lock
+++ b/.github/locks/osx-64_test_lab3.5_py3.11.conda.lock
@@ -36,9 +36,9 @@
 
 @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/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
 https://conda.anaconda.org/conda-forge/osx-64/icu-72.1-h7336db1_0.conda#c9689510a50a4bb2ae978421671a125e
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.5.0-hf0c8a7f_1.conda#6c81cb022780ee33435cca0127dd43c9
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
 https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#691d103d11180486154af49c037b7ed9
@@ -51,10 +51,10 @@ https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.11-3_cp311.conda#5e0a
 https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda#939e3e74d8be4dac89ce83b20de2492a
 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/firefox-102.10.0esr-hf0c8a7f_0.conda#52e68cb8ad4770651020fcab425b0b99
+https://conda.anaconda.org/conda-forge/osx-64/firefox-102.11.0esr-he965462_0.conda#bf6f4386389cee37e4bd9cd55e3b663c
 https://conda.anaconda.org/conda-forge/osx-64/geckodriver-0.33.0-hf46a32e_0.conda#897200360380560ac85cf0756161dd78
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3
-https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.4-h554bb67_0.conda#003fef825b16c26c44d97e115bf8840e
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
 https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e
@@ -65,10 +65,10 @@ https://conda.anaconda.org/conda-forge/osx-64/libxslt-1.1.37-h5d22bc9_0.tar.bz2#
 https://conda.anaconda.org/conda-forge/osx-64/python-3.11.3-h99528f9_0_cpython.conda#c3291f9411424fc587d53a2ea57fb075
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -204,7 +204,7 @@ https://conda.anaconda.org/conda-forge/noarch/trio-websocket-0.10.2-pyhd8ed1ab_0
 https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.2.0-pyhd8ed1ab_0.conda#58ca2d50c3b27b86fd7df62eaadbf9a9
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.8.0-pyhd8ed1ab_0.conda#1ca43103a08456b19222d93fd9d119ac
 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-2.0.1-py311hab14417_0.conda#cd9a03d6202f518e2fcb6720ddba19f7
+https://conda.anaconda.org/conda-forge/osx-64/pandas-2.0.1-py311hab14417_1.conda#618f01d1356c3443fa11378ab44dd7a4
 https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.38-hd8ed1ab_0.conda#45b74f64d8808eda7e6f6e6b1d641fd2
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/pytest-json-report-1.5.0-pyhd8ed1ab_0.tar.bz2#837e335fa428cf7c784ee2e80594506c
@@ -213,18 +213,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyhd1c38e8_0.conda#30960117dd6bd242aec8428a1004b167
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.2-pyh736e0ef_0.conda#aa43ffb10a39d9eb2538761a3f838a87
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/osx-64_test_lab3.5_py3.8.conda.lock b/.github/locks/osx-64_test_lab3.5_py3.8.conda.lock
index 8b138802..5633cfac 100644
--- a/.github/locks/osx-64_test_lab3.5_py3.8.conda.lock
+++ b/.github/locks/osx-64_test_lab3.5_py3.8.conda.lock
@@ -37,9 +37,9 @@
 
 @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/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
 https://conda.anaconda.org/conda-forge/osx-64/icu-72.1-h7336db1_0.conda#c9689510a50a4bb2ae978421671a125e
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
 https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#691d103d11180486154af49c037b7ed9
 https://conda.anaconda.org/conda-forge/osx-64/libsodium-1.0.18-hbcb3906_1.tar.bz2#24632c09ed931af617fe6d5292919cab
@@ -50,10 +50,10 @@ https://conda.anaconda.org/conda-forge/osx-64/pandoc-2.19.2-h694c41f_2.conda#de3
 https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.8-3_cp38.conda#ff192f59f7fe23555612030493a079f8
 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/firefox-102.10.0esr-hf0c8a7f_0.conda#52e68cb8ad4770651020fcab425b0b99
+https://conda.anaconda.org/conda-forge/osx-64/firefox-102.11.0esr-he965462_0.conda#bf6f4386389cee37e4bd9cd55e3b663c
 https://conda.anaconda.org/conda-forge/osx-64/geckodriver-0.33.0-hf46a32e_0.conda#897200360380560ac85cf0756161dd78
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3
-https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.4-h554bb67_0.conda#003fef825b16c26c44d97e115bf8840e
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
 https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e
@@ -64,10 +64,10 @@ https://conda.anaconda.org/conda-forge/osx-64/libxslt-1.1.37-h5d22bc9_0.tar.bz2#
 https://conda.anaconda.org/conda-forge/osx-64/python-3.8.16-hf9b03c3_1_cpython.conda#96d23d997c18a90efde924d9ca6dd5b3
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -211,18 +211,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyhd1c38e8_0.conda#acc618532cbc899f5721cc96407b16cc
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.2-pyh736e0ef_0.conda#aa43ffb10a39d9eb2538761a3f838a87
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/osx-64_test_lab3.6_py3.11.conda.lock b/.github/locks/osx-64_test_lab3.6_py3.11.conda.lock
index 27c1b620..2669d63f 100644
--- a/.github/locks/osx-64_test_lab3.6_py3.11.conda.lock
+++ b/.github/locks/osx-64_test_lab3.6_py3.11.conda.lock
@@ -34,9 +34,9 @@
 
 @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/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
 https://conda.anaconda.org/conda-forge/osx-64/icu-72.1-h7336db1_0.conda#c9689510a50a4bb2ae978421671a125e
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libexpat-2.5.0-hf0c8a7f_1.conda#6c81cb022780ee33435cca0127dd43c9
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
 https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#691d103d11180486154af49c037b7ed9
@@ -49,10 +49,10 @@ https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.11-3_cp311.conda#5e0a
 https://conda.anaconda.org/conda-forge/noarch/tzdata-2023c-h71feb2d_0.conda#939e3e74d8be4dac89ce83b20de2492a
 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/firefox-102.10.0esr-hf0c8a7f_0.conda#52e68cb8ad4770651020fcab425b0b99
+https://conda.anaconda.org/conda-forge/osx-64/firefox-102.11.0esr-he965462_0.conda#bf6f4386389cee37e4bd9cd55e3b663c
 https://conda.anaconda.org/conda-forge/osx-64/geckodriver-0.33.0-hf46a32e_0.conda#897200360380560ac85cf0756161dd78
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3
-https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.4-h554bb67_0.conda#003fef825b16c26c44d97e115bf8840e
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
 https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e
@@ -64,10 +64,10 @@ https://conda.anaconda.org/conda-forge/osx-64/python-3.11.3-h99528f9_0_cpython.c
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -96,7 +96,7 @@ https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.0.5-py311hd2070f0
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.11-py311h52ff4d3_0.conda#74ea1a8d16b3290cd492da6f683ef8fd
+https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.12-py311h52ff4d3_0.conda#1acaddcf7e60378c29b693bb4360c6b2
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -208,7 +208,7 @@ https://conda.anaconda.org/conda-forge/noarch/ypy-websocket-0.8.2-pyhd8ed1ab_0.c
 https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.2.0-pyhd8ed1ab_0.conda#58ca2d50c3b27b86fd7df62eaadbf9a9
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.8.0-pyhd8ed1ab_0.conda#1ca43103a08456b19222d93fd9d119ac
 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-2.0.1-py311hab14417_0.conda#cd9a03d6202f518e2fcb6720ddba19f7
+https://conda.anaconda.org/conda-forge/osx-64/pandas-2.0.1-py311hab14417_1.conda#618f01d1356c3443fa11378ab44dd7a4
 https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.38-hd8ed1ab_0.conda#45b74f64d8808eda7e6f6e6b1d641fd2
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/pytest-json-report-1.5.0-pyhd8ed1ab_0.tar.bz2#837e335fa428cf7c784ee2e80594506c
@@ -217,19 +217,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyhd1c38e8_0.conda#30960117dd6bd242aec8428a1004b167
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh736e0ef_0.conda#3bbe4a71a9d5d8e13c1504e3cd077b32
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh736e0ef_0.conda#6568402ca7540ad5b352fb51ffe17b51
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/osx-64_test_lab3.6_py3.8.conda.lock b/.github/locks/osx-64_test_lab3.6_py3.8.conda.lock
index 13158eae..4de7d37e 100644
--- a/.github/locks/osx-64_test_lab3.6_py3.8.conda.lock
+++ b/.github/locks/osx-64_test_lab3.6_py3.8.conda.lock
@@ -35,9 +35,9 @@
 
 @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/ca-certificates-2022.12.7-h033912b_0.conda#af2bdcd68f16ce030ca957cdeb83d88a
+https://conda.anaconda.org/conda-forge/osx-64/ca-certificates-2023.5.7-h8857fd0_0.conda#b704e4b79ba0d887c4870b7b09d6a4df
 https://conda.anaconda.org/conda-forge/osx-64/icu-72.1-h7336db1_0.conda#c9689510a50a4bb2ae978421671a125e
-https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.2-hd57cbcb_0.conda#115c699171430d88dd8b7444fe086bbf
+https://conda.anaconda.org/conda-forge/osx-64/libcxx-16.0.3-hd57cbcb_0.conda#a18d8a09f5f3037723862e5ffd3d8efa
 https://conda.anaconda.org/conda-forge/osx-64/libffi-3.4.2-h0d85af4_5.tar.bz2#ccb34fb14960ad8b125962d3d79b31a9
 https://conda.anaconda.org/conda-forge/osx-64/libiconv-1.17-hac89ed1_0.tar.bz2#691d103d11180486154af49c037b7ed9
 https://conda.anaconda.org/conda-forge/osx-64/libsodium-1.0.18-hbcb3906_1.tar.bz2#24632c09ed931af617fe6d5292919cab
@@ -48,10 +48,10 @@ https://conda.anaconda.org/conda-forge/osx-64/pandoc-2.19.2-h694c41f_2.conda#de3
 https://conda.anaconda.org/conda-forge/osx-64/python_abi-3.8-3_cp38.conda#ff192f59f7fe23555612030493a079f8
 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/firefox-102.10.0esr-hf0c8a7f_0.conda#52e68cb8ad4770651020fcab425b0b99
+https://conda.anaconda.org/conda-forge/osx-64/firefox-102.11.0esr-he965462_0.conda#bf6f4386389cee37e4bd9cd55e3b663c
 https://conda.anaconda.org/conda-forge/osx-64/geckodriver-0.33.0-hf46a32e_0.conda#897200360380560ac85cf0756161dd78
 https://conda.anaconda.org/conda-forge/osx-64/libgfortran5-12.2.0-he409387_31.conda#5a544130e584b1f204ac896ff071d5b3
-https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.40.0-ha978bb4_1.conda#3fe0656cc909897be258fb2aa33537b7
+https://conda.anaconda.org/conda-forge/osx-64/libsqlite-3.41.2-h58db7d2_1.conda#208f91c5db1ba9f80d32cffde56f4a8f
 https://conda.anaconda.org/conda-forge/osx-64/libxml2-2.10.4-h554bb67_0.conda#003fef825b16c26c44d97e115bf8840e
 https://conda.anaconda.org/conda-forge/osx-64/openssl-3.1.0-h8a1eda9_3.conda#3761d72a2a68de6fd1c0a2d038864785
 https://conda.anaconda.org/conda-forge/osx-64/readline-8.2-h9e318b2_1.conda#f17f77f2acf4d344734bda76829ce14e
@@ -63,10 +63,10 @@ https://conda.anaconda.org/conda-forge/osx-64/python-3.8.16-hf9b03c3_1_cpython.c
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/appnope-0.1.3-pyhd8ed1ab_0.tar.bz2#54ac328d703bff191256ffa1183126d1
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/click-8.1.3-unix_pyhd8ed1ab_2.tar.bz2#20e4087407c7cb04a40817114b333dbf
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
@@ -95,7 +95,7 @@ https://conda.anaconda.org/conda-forge/osx-64/msgpack-python-1.0.5-py38h98b9b1b_
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.11-py38h3b04eb0_0.conda#18f0255799c02eda957da983b8ac6afd
+https://conda.anaconda.org/conda-forge/osx-64/orjson-3.8.12-py38h3b04eb0_0.conda#f84ce9bea0e3c550f1bc00af5be39c84
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -215,19 +215,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyhd1c38e8_0.conda#acc618532cbc899f5721cc96407b16cc
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh736e0ef_0.conda#3bbe4a71a9d5d8e13c1504e3cd077b32
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh736e0ef_0.conda#6568402ca7540ad5b352fb51ffe17b51
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/win-64_test_lab3.5_py3.11.conda.lock b/.github/locks/win-64_test_lab3.5_py3.11.conda.lock
index 165308ae..67fa958b 100644
--- a/.github/locks/win-64_test_lab3.5_py3.11.conda.lock
+++ b/.github/locks/win-64_test_lab3.5_py3.11.conda.lock
@@ -36,7 +36,7 @@
 #   - traittypes
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/win-64/libexpat-2.5.0-h63175ca_1.conda#636cc3cbbd2e28bcfd2f73b2044aac2c
 https://conda.anaconda.org/conda-forge/noarch/llvm-meta-5.0.0-0.tar.bz2#213b5b5ad34008147a824460e50a691c
 https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2#9a66894dfd07c4510beb6b3f9672ccc0
@@ -49,12 +49,12 @@ https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.34.31931-h5081d32_
 https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb25d44b_16.conda#ea326b37e3bd6d2616988e09f3a9396c
 https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.34.31931-hed1258a_16.conda#0374eae69b6dbfb27c3dc27167109eb4
 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9
-https://conda.anaconda.org/conda-forge/win-64/firefox-102.10.0esr-h63175ca_0.conda#a53c1459c65768ba48481a186ceed34b
+https://conda.anaconda.org/conda-forge/win-64/firefox-102.11.0esr-h63175ca_0.conda#12ea043f0413a98078731e9f0657c776
 https://conda.anaconda.org/conda-forge/win-64/geckodriver-0.33.0-h611cf2b_0.conda#e5ad5ec7f6140c1fdf9bd2a7927a4f91
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
 https://conda.anaconda.org/conda-forge/win-64/libsodium-1.0.18-h8d14728_1.tar.bz2#5c1fb45b5e2912c19098750ae8a32604
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/openmp-5.0.0-vc14_1.tar.bz2#8284c925330fa53668ade00db3c9e787
 https://conda.anaconda.org/conda-forge/win-64/openssl-3.1.0-hcfcfb64_3.conda#70ef20ae131da584481da2fbc6aa31c8
@@ -66,10 +66,10 @@ https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.4-hc3477c8_0.conda#d9
 https://conda.anaconda.org/conda-forge/win-64/python-3.11.3-h2628c8c_0_cpython.conda#8f82e0e0ba51bed311f28eb6450393f6
 https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.4-h0e60522_1.tar.bz2#e1aff0583dda5fb917eb3d2c1025aa80
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -205,7 +205,7 @@ https://conda.anaconda.org/conda-forge/noarch/trio-websocket-0.10.2-pyhd8ed1ab_0
 https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.2.0-pyhd8ed1ab_0.conda#58ca2d50c3b27b86fd7df62eaadbf9a9
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.8.0-pyhd8ed1ab_0.conda#1ca43103a08456b19222d93fd9d119ac
 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-2.0.1-py311hf63dbb6_0.conda#00052d983770902d3dac8097c1b82e67
+https://conda.anaconda.org/conda-forge/win-64/pandas-2.0.1-py311hf63dbb6_1.conda#509562c4360e4cdd30ff1c2d9789f205
 https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.38-hd8ed1ab_0.conda#45b74f64d8808eda7e6f6e6b1d641fd2
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/pytest-json-report-1.5.0-pyhd8ed1ab_0.tar.bz2#837e335fa428cf7c784ee2e80594506c
@@ -214,18 +214,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyh08f2357_0.conda#aebd5e79c0f354cdbceb055cdec53659
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.3-pyh025b116_0.conda#d33b22490fee39bf6462424a3ea34aba
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/win-64_test_lab3.5_py3.8.conda.lock b/.github/locks/win-64_test_lab3.5_py3.8.conda.lock
index 1c82f4d5..0c4a28dd 100644
--- a/.github/locks/win-64_test_lab3.5_py3.8.conda.lock
+++ b/.github/locks/win-64_test_lab3.5_py3.8.conda.lock
@@ -37,7 +37,7 @@
 #   - traittypes
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/noarch/llvm-meta-5.0.0-0.tar.bz2#213b5b5ad34008147a824460e50a691c
 https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2#9a66894dfd07c4510beb6b3f9672ccc0
 https://conda.anaconda.org/conda-forge/win-64/pandoc-2.19.2-h57928b3_2.conda#c188f67e94153ddc7e4e10ae127cbb1a
@@ -48,12 +48,12 @@ https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.34.31931-h5081d32_
 https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb25d44b_16.conda#ea326b37e3bd6d2616988e09f3a9396c
 https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.34.31931-hed1258a_16.conda#0374eae69b6dbfb27c3dc27167109eb4
 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9
-https://conda.anaconda.org/conda-forge/win-64/firefox-102.10.0esr-h63175ca_0.conda#a53c1459c65768ba48481a186ceed34b
+https://conda.anaconda.org/conda-forge/win-64/firefox-102.11.0esr-h63175ca_0.conda#12ea043f0413a98078731e9f0657c776
 https://conda.anaconda.org/conda-forge/win-64/geckodriver-0.33.0-h611cf2b_0.conda#e5ad5ec7f6140c1fdf9bd2a7927a4f91
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
 https://conda.anaconda.org/conda-forge/win-64/libsodium-1.0.18-h8d14728_1.tar.bz2#5c1fb45b5e2912c19098750ae8a32604
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/openmp-5.0.0-vc14_1.tar.bz2#8284c925330fa53668ade00db3c9e787
 https://conda.anaconda.org/conda-forge/win-64/openssl-3.1.0-hcfcfb64_3.conda#70ef20ae131da584481da2fbc6aa31c8
@@ -65,10 +65,10 @@ https://conda.anaconda.org/conda-forge/win-64/libxml2-2.10.4-hc3477c8_0.conda#d9
 https://conda.anaconda.org/conda-forge/win-64/python-3.8.16-h4de0772_1_cpython.conda#461d9fc92cfde68f2ca7ef0988f6326a
 https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.4-h0e60522_1.tar.bz2#e1aff0583dda5fb917eb3d2c1025aa80
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -212,18 +212,18 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyh08f2357_0.conda#f289f9dc26526b8bd9f5845486f53a4d
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
 https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.21.3-pyh025b116_0.conda#d33b22490fee39bf6462424a3ea34aba
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.4-pyhd8ed1ab_0.conda#9dea5ab3cc33084f7a3680a98859731e
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/nbclassic-1.0.0-pyhb4ecaf3_1.conda#a0be31e9bd84d6eae87cdbf74c56b90b
diff --git a/.github/locks/win-64_test_lab3.6_py3.11.conda.lock b/.github/locks/win-64_test_lab3.6_py3.11.conda.lock
index fbd53909..51c4218a 100644
--- a/.github/locks/win-64_test_lab3.6_py3.11.conda.lock
+++ b/.github/locks/win-64_test_lab3.6_py3.11.conda.lock
@@ -34,7 +34,7 @@
 #   - traittypes
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/win-64/libexpat-2.5.0-h63175ca_1.conda#636cc3cbbd2e28bcfd2f73b2044aac2c
 https://conda.anaconda.org/conda-forge/noarch/llvm-meta-5.0.0-0.tar.bz2#213b5b5ad34008147a824460e50a691c
 https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2#9a66894dfd07c4510beb6b3f9672ccc0
@@ -47,12 +47,12 @@ https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.34.31931-h5081d32_
 https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb25d44b_16.conda#ea326b37e3bd6d2616988e09f3a9396c
 https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.34.31931-hed1258a_16.conda#0374eae69b6dbfb27c3dc27167109eb4
 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9
-https://conda.anaconda.org/conda-forge/win-64/firefox-102.10.0esr-h63175ca_0.conda#a53c1459c65768ba48481a186ceed34b
+https://conda.anaconda.org/conda-forge/win-64/firefox-102.11.0esr-h63175ca_0.conda#12ea043f0413a98078731e9f0657c776
 https://conda.anaconda.org/conda-forge/win-64/geckodriver-0.33.0-h611cf2b_0.conda#e5ad5ec7f6140c1fdf9bd2a7927a4f91
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
 https://conda.anaconda.org/conda-forge/win-64/libsodium-1.0.18-h8d14728_1.tar.bz2#5c1fb45b5e2912c19098750ae8a32604
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/openmp-5.0.0-vc14_1.tar.bz2#8284c925330fa53668ade00db3c9e787
 https://conda.anaconda.org/conda-forge/win-64/openssl-3.1.0-hcfcfb64_3.conda#70ef20ae131da584481da2fbc6aa31c8
@@ -65,10 +65,10 @@ https://conda.anaconda.org/conda-forge/win-64/python-3.11.3-h2628c8c_0_cpython.c
 https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.4-h0e60522_1.tar.bz2#e1aff0583dda5fb917eb3d2c1025aa80
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -96,7 +96,7 @@ https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.0.5-py311h005e61a
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.11-py311h5443569_0.conda#9c1bd04b7c98b86b362a0f0c9716d34d
+https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.12-py311h5443569_0.conda#6c843e80610cfbf3f4c59a56d9a25d58
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -209,7 +209,7 @@ https://conda.anaconda.org/conda-forge/noarch/ypy-websocket-0.8.2-pyhd8ed1ab_0.c
 https://conda.anaconda.org/conda-forge/noarch/jupyter_client-8.2.0-pyhd8ed1ab_0.conda#58ca2d50c3b27b86fd7df62eaadbf9a9
 https://conda.anaconda.org/conda-forge/noarch/nbformat-5.8.0-pyhd8ed1ab_0.conda#1ca43103a08456b19222d93fd9d119ac
 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-2.0.1-py311hf63dbb6_0.conda#00052d983770902d3dac8097c1b82e67
+https://conda.anaconda.org/conda-forge/win-64/pandas-2.0.1-py311hf63dbb6_1.conda#509562c4360e4cdd30ff1c2d9789f205
 https://conda.anaconda.org/conda-forge/noarch/prompt_toolkit-3.0.38-hd8ed1ab_0.conda#45b74f64d8808eda7e6f6e6b1d641fd2
 https://conda.anaconda.org/conda-forge/noarch/pytest-html-3.2.0-pyhd8ed1ab_1.tar.bz2#d5c7a941dfbceaab4b172a56d7918eb0
 https://conda.anaconda.org/conda-forge/noarch/pytest-json-report-1.5.0-pyhd8ed1ab_0.tar.bz2#837e335fa428cf7c784ee2e80594506c
@@ -218,19 +218,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.13.2-pyh08f2357_0.conda#aebd5e79c0f354cdbceb055cdec53659
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh025b116_0.conda#4d594953555f43826532ab5c5f7754f5
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh025b116_0.conda#94be25e827144cc4263ee2c81ae01bd2
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/.github/locks/win-64_test_lab3.6_py3.8.conda.lock b/.github/locks/win-64_test_lab3.6_py3.8.conda.lock
index 1475d1fa..e48ec0cf 100644
--- a/.github/locks/win-64_test_lab3.6_py3.8.conda.lock
+++ b/.github/locks/win-64_test_lab3.6_py3.8.conda.lock
@@ -35,7 +35,7 @@
 #   - traittypes
 
 @EXPLICIT
-https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2022.12.7-h5b45459_0.conda#31de4d9887dc8eaed9e6230a5dfbb9d6
+https://conda.anaconda.org/conda-forge/win-64/ca-certificates-2023.5.7-h56e8100_0.conda#604212634bd8c4d6f20d44b946e8eedb
 https://conda.anaconda.org/conda-forge/noarch/llvm-meta-5.0.0-0.tar.bz2#213b5b5ad34008147a824460e50a691c
 https://conda.anaconda.org/conda-forge/noarch/nomkl-1.0-h5ca1d4c_0.tar.bz2#9a66894dfd07c4510beb6b3f9672ccc0
 https://conda.anaconda.org/conda-forge/win-64/pandoc-2.19.2-h57928b3_2.conda#c188f67e94153ddc7e4e10ae127cbb1a
@@ -46,12 +46,12 @@ https://conda.anaconda.org/conda-forge/win-64/vc14_runtime-14.34.31931-h5081d32_
 https://conda.anaconda.org/conda-forge/win-64/vc-14.3-hb25d44b_16.conda#ea326b37e3bd6d2616988e09f3a9396c
 https://conda.anaconda.org/conda-forge/win-64/vs2015_runtime-14.34.31931-hed1258a_16.conda#0374eae69b6dbfb27c3dc27167109eb4
 https://conda.anaconda.org/conda-forge/win-64/bzip2-1.0.8-h8ffe710_4.tar.bz2#7c03c66026944073040cb19a4f3ec3c9
-https://conda.anaconda.org/conda-forge/win-64/firefox-102.10.0esr-h63175ca_0.conda#a53c1459c65768ba48481a186ceed34b
+https://conda.anaconda.org/conda-forge/win-64/firefox-102.11.0esr-h63175ca_0.conda#12ea043f0413a98078731e9f0657c776
 https://conda.anaconda.org/conda-forge/win-64/geckodriver-0.33.0-h611cf2b_0.conda#e5ad5ec7f6140c1fdf9bd2a7927a4f91
 https://conda.anaconda.org/conda-forge/win-64/libffi-3.4.2-h8ffe710_5.tar.bz2#2c96d1b6915b408893f9472569dee135
 https://conda.anaconda.org/conda-forge/win-64/libiconv-1.17-h8ffe710_0.tar.bz2#050119977a86e4856f0416e2edcf81bb
 https://conda.anaconda.org/conda-forge/win-64/libsodium-1.0.18-h8d14728_1.tar.bz2#5c1fb45b5e2912c19098750ae8a32604
-https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_1.conda#2832b5d2aa943a96b5046cfab01d2462
+https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.41.2-hcfcfb64_1.conda#aa000e5bc50d73577a62b9f8c996a8dd
 https://conda.anaconda.org/conda-forge/win-64/libzlib-1.2.13-hcfcfb64_4.tar.bz2#0cc5c5cc64ee1637f37f8540a175854c
 https://conda.anaconda.org/conda-forge/win-64/openmp-5.0.0-vc14_1.tar.bz2#8284c925330fa53668ade00db3c9e787
 https://conda.anaconda.org/conda-forge/win-64/openssl-3.1.0-hcfcfb64_3.conda#70ef20ae131da584481da2fbc6aa31c8
@@ -64,10 +64,10 @@ https://conda.anaconda.org/conda-forge/win-64/python-3.8.16-h4de0772_1_cpython.c
 https://conda.anaconda.org/conda-forge/win-64/zeromq-4.3.4-h0e60522_1.tar.bz2#e1aff0583dda5fb917eb3d2c1025aa80
 https://conda.anaconda.org/conda-forge/noarch/aiofiles-22.1.0-pyhd8ed1ab_0.tar.bz2#a88c206fdb78e34adb1c4081f5f838dd
 https://conda.anaconda.org/conda-forge/noarch/async_generator-1.10-py_0.tar.bz2#d56c596e61b1c4952acf0a9920856c12
-https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_0.conda#96dc713c727993c72605686c322a9fc8
+https://conda.anaconda.org/conda-forge/noarch/attrs-23.1.0-pyh71513ae_1.conda#3edfead7cedd1ab4400a6c588f3e75f8
 https://conda.anaconda.org/conda-forge/noarch/backcall-0.2.0-pyh9f0ad1d_0.tar.bz2#6006a6d08a3fa99268a2681c7fb55213
 https://conda.anaconda.org/conda-forge/noarch/backports-1.0-pyhd8ed1ab_3.conda#54ca2e08b3220c148a1d8329c2678e02
-https://conda.anaconda.org/conda-forge/noarch/certifi-2022.12.7-pyhd8ed1ab_0.conda#fb9addc3db06e56abe03e0e9f21a63e6
+https://conda.anaconda.org/conda-forge/noarch/certifi-2023.5.7-pyhd8ed1ab_0.conda#5d1b71c942b8421285934dad1d891ebc
 https://conda.anaconda.org/conda-forge/noarch/charset-normalizer-3.1.0-pyhd8ed1ab_0.conda#7fcff9f6f123696e940bda77bd4d6551
 https://conda.anaconda.org/conda-forge/noarch/cloudpickle-2.2.1-pyhd8ed1ab_0.conda#b325bfc4cff7d7f8a868f1f7ecc4ed16
 https://conda.anaconda.org/conda-forge/noarch/colorama-0.4.6-pyhd8ed1ab_0.tar.bz2#3faab06a954c2a04039983f2c4a50d99
@@ -95,7 +95,7 @@ https://conda.anaconda.org/conda-forge/win-64/msgpack-python-1.0.5-py38hb1fd069_
 https://conda.anaconda.org/conda-forge/noarch/natsort-8.3.1-pyhd8ed1ab_0.conda#8c53149aa69bfeb045f28c92a2b2ddc7
 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-3.1-pyhd8ed1ab_0.conda#254f787d5068bc89f578bf63893ce8b4
-https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.11-py38he30244c_0.conda#f2a70ff7b782b01a2ca29d9ae5996ced
+https://conda.anaconda.org/conda-forge/win-64/orjson-3.8.12-py38he30244c_0.conda#1c72dd0aed961b38d1f06fbdb7f03fe3
 https://conda.anaconda.org/conda-forge/noarch/packaging-23.1-pyhd8ed1ab_0.conda#91cda59e66e1e4afe9476f8ef98f5c30
 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
@@ -216,19 +216,19 @@ https://conda.anaconda.org/conda-forge/noarch/urllib3-1.26.15-pyhd8ed1ab_0.conda
 https://conda.anaconda.org/conda-forge/noarch/ipython-8.12.2-pyh08f2357_0.conda#f289f9dc26526b8bd9f5845486f53a4d
 https://conda.anaconda.org/conda-forge/noarch/nbclient-0.7.4-pyhd8ed1ab_0.conda#f7aa15f77d29b11caa1df1eb15383c59
 https://conda.anaconda.org/conda-forge/noarch/requests-2.29.0-pyhd8ed1ab_0.conda#5fa992d972fbccfc069161805122cb8d
-https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.0-pyhd8ed1ab_0.conda#9626454456249ff3fb0cb5b902c5220d
-https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.22.0-pyh025b116_0.conda#4d594953555f43826532ab5c5f7754f5
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.3.1-pyhd8ed1ab_0.conda#1cd37f906fc423d6ebf6fd63c1a49290
+https://conda.anaconda.org/conda-forge/noarch/selenium-4.9.1-pyhd8ed1ab_0.conda#b3daee1b09922328cfa11b4761cf1adf
+https://conda.anaconda.org/conda-forge/noarch/ipykernel-6.23.0-pyh025b116_0.conda#94be25e827144cc4263ee2c81ae01bd2
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-core-7.4.0-pyhd8ed1ab_0.conda#4456e6030a8309bdad57569b0170b6a3
 https://conda.anaconda.org/conda-forge/noarch/robotframework-seleniumlibrary-6.1.0-pyhd8ed1ab_0.conda#15700afca8f7ab35542e9c1af63568f1
 https://conda.anaconda.org/conda-forge/noarch/ipywidgets-8.0.6-pyhd8ed1ab_0.conda#68627a08556e4a273e4c7bfc84251457
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server-2.5.0-pyhd8ed1ab_0.conda#7fa3bd3d8dee42934f63711e9fbe959a
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.3.1-pyhd8ed1ab_0.conda#28d58c9f73807af6cf19cab5d1d51b47
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-pandoc-7.4.0-pyhd8ed1ab_0.conda#127c702e1b1eff595be82bc6a78cfce0
 https://conda.anaconda.org/conda-forge/noarch/robotframework-jupyterlibrary-0.4.2-pyhd8ed1ab_0.conda#6687f0def03dc3db713149fb8e026068
 https://conda.anaconda.org/conda-forge/noarch/bqplot-0.12.39-pyhd8ed1ab_0.conda#f7455264455f8b225034af96269ca78d
 https://conda.anaconda.org/conda-forge/noarch/ipylab-0.7.1-pyhd8ed1ab_1.conda#fd19f67b01ac2ed4d6354c8ae732f889
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_fileid-0.9.0-pyhd8ed1ab_0.conda#a12525b037a703d7f4512da737d700e6
 https://conda.anaconda.org/conda-forge/noarch/jupyterlab_server-2.22.1-pyhd8ed1ab_0.conda#fc7172a6742a7c3c4331ddd7ed463ffc
-https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.3.1-pyhd8ed1ab_0.conda#42131a78cf4826ee071afab7d29442ce
+https://conda.anaconda.org/conda-forge/noarch/nbconvert-7.4.0-pyhd8ed1ab_0.conda#a86727968b41c20dd3d73b91632e77dc
 https://conda.anaconda.org/conda-forge/noarch/notebook-shim-0.2.3-pyhd8ed1ab_0.conda#67e0fe74c156267d9159e9133df7fd37
 https://conda.anaconda.org/conda-forge/noarch/ipydatagrid-1.1.15-pyhd8ed1ab_0.conda#c4159b17417ac2a21f63f85384255c51
 https://conda.anaconda.org/conda-forge/noarch/jupyter_server_ydoc-0.8.0-pyhd8ed1ab_0.conda#780280d42fbcb2eaf654a6ba7a3e5bb5
diff --git a/atest/API/06_Scales_ForceGraph.robot b/atest/API/06_Scales_ForceGraph.robot
new file mode 100644
index 00000000..fe8267b7
--- /dev/null
+++ b/atest/API/06_Scales_ForceGraph.robot
@@ -0,0 +1,62 @@
+*** Settings ***
+Resource        ../_resources/keywords/Server.robot
+Resource        ../_resources/keywords/Browser.robot
+Resource        ../_resources/keywords/Lab.robot
+Resource        ../_resources/keywords/IPyForceGraph.robot
+Resource        ../_resources/keywords/Screenshots.robot
+Library         Collections
+Library         JupyterLibrary
+Library         OperatingSystem
+
+Force Tags      suite:scales
+
+
+*** Variables ***
+${SCREENS}      ${SCREENS ROOT}${/}api
+
+
+*** Test Cases ***
+ContinuousColor Can Update ForceGraph Nodes
+    Scale Works As Expected    ForceGraph    ContinuousColor    viridis
+
+OrdinalColor Can Update ForceGraph Nodes
+    Scale Works As Expected    ForceGraph    OrdinalColor    category10
+
+
+*** Keywords ***
+Scale Works As Expected
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    ${screens} =    Set Variable    ${SCREENS}${/}${widget_class.lower()}_${scale_class}
+    Maybe Skip A Test    widget_class=${widget_class}    feature=${scale_class}
+    Set Screenshot Directory    ${screens}
+    Set Up Scale Example    ${widget_class}    ${scale_class}    ${scheme}
+    ${frame} =    Set Variable    css:${IPYFORCEGRAPH FRAME}
+    ${transparent} =    Get Element Screenshot Size    ${frame}    ${screens}    01-transparent.png
+    Add And Run JupyterLab Code Cell
+    ...    ns.color = scale
+    Wait For All Cells To Run
+    Sleep    1s
+    ${color} =    Get Element Screenshot Size    ${frame}    ${screens}    02-scale.png
+    Should Be True Or Screenshot    ${color} > ${transparent}    03-scale-bigger-than-transparent.png
+    [Teardown]    Clean Up Scale Example
+
+Set Up Scale Example
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    Set Tags    scale:${scale_class}    widget:${widget_class.lower()}
+    ${text} =    Get File    ${IPYFORCEGRAPH_FIXTURES}${/}api${/}Scales.py
+    ${text} =    Set Variable    ${text.replace("WIDGET_CLASS", "${widget_class}")}
+    ${text} =    Set Variable    ${text.replace("SCALE_CLASS", "${scale_class}")}
+    ${text} =    Set Variable    ${text.replace("SCHEME", "${scheme}")}
+    Launch A New JupyterLab Document
+    Set CodeMirror Value    .jp-CodeCell .CodeMirror    ${text.strip()}
+    Execute JupyterLab Command    Show Log Console
+    Execute JupyterLab Command    Run All Cells
+    Wait Until Force Graph Is Visible
+    Capture Page Screenshot    00-start.png
+
+Clean Up Scale Example
+    Capture Page Screenshot    99-fin.png
+    ${nb_dir} =    Get Jupyter Directory
+    Remove File    ${nb_dir}${/}Untitled.ipynb
+    Refresh File List
+    Try To Close All Tabs
diff --git a/atest/API/06_Scales_ForceGraph3D.robot b/atest/API/06_Scales_ForceGraph3D.robot
new file mode 100644
index 00000000..f61116d2
--- /dev/null
+++ b/atest/API/06_Scales_ForceGraph3D.robot
@@ -0,0 +1,62 @@
+*** Settings ***
+Resource        ../_resources/keywords/Server.robot
+Resource        ../_resources/keywords/Browser.robot
+Resource        ../_resources/keywords/Lab.robot
+Resource        ../_resources/keywords/IPyForceGraph.robot
+Resource        ../_resources/keywords/Screenshots.robot
+Library         Collections
+Library         JupyterLibrary
+Library         OperatingSystem
+
+Force Tags      suite:scales
+
+
+*** Variables ***
+${SCREENS}      ${SCREENS ROOT}${/}api
+
+
+*** Test Cases ***
+ContinuousColor Can Update ForceGraph3D Nodes
+    Scale Works As Expected    ForceGraph3D    ContinuousColor    viridis
+
+OrdinalColor Can Update ForceGraph3D Nodes
+    Scale Works As Expected    ForceGraph3D    OrdinalColor    category10
+
+
+*** Keywords ***
+Scale Works As Expected
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    ${screens} =    Set Variable    ${SCREENS}${/}${widget_class.lower()}_${scale_class}
+    Maybe Skip A Test    widget_class=${widget_class}    feature=${scale_class}
+    Set Screenshot Directory    ${screens}
+    Set Up Scale Example    ${widget_class}    ${scale_class}    ${scheme}
+    ${frame} =    Set Variable    css:${IPYFORCEGRAPH FRAME}
+    ${transparent} =    Get Element Screenshot Size    ${frame}    ${screens}    01-transparent.png
+    Add And Run JupyterLab Code Cell
+    ...    ns.color = scale
+    Wait For All Cells To Run
+    Sleep    1s
+    ${color} =    Get Element Screenshot Size    ${frame}    ${screens}    02-scale.png
+    Should Be True Or Screenshot    ${color} > ${transparent}    03-scale-bigger-than-transparent.png
+    [Teardown]    Clean Up Scale Example
+
+Set Up Scale Example
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    Set Tags    scale:${scale_class}    widget:${widget_class.lower()}
+    ${text} =    Get File    ${IPYFORCEGRAPH_FIXTURES}${/}api${/}Scales.py
+    ${text} =    Set Variable    ${text.replace("WIDGET_CLASS", "${widget_class}")}
+    ${text} =    Set Variable    ${text.replace("SCALE_CLASS", "${scale_class}")}
+    ${text} =    Set Variable    ${text.replace("SCHEME", "${scheme}")}
+    Launch A New JupyterLab Document
+    Set CodeMirror Value    .jp-CodeCell .CodeMirror    ${text.strip()}
+    Execute JupyterLab Command    Show Log Console
+    Execute JupyterLab Command    Run All Cells
+    Wait Until Force Graph Is Visible
+    Capture Page Screenshot    00-start.png
+
+Clean Up Scale Example
+    Capture Page Screenshot    99-fin.png
+    ${nb_dir} =    Get Jupyter Directory
+    Remove File    ${nb_dir}${/}Untitled.ipynb
+    Refresh File List
+    Try To Close All Tabs
diff --git a/atest/API/06_Scales_GRAPH.robot.j2 b/atest/API/06_Scales_GRAPH.robot.j2
new file mode 100644
index 00000000..da260332
--- /dev/null
+++ b/atest/API/06_Scales_GRAPH.robot.j2
@@ -0,0 +1,60 @@
+*** Settings ***
+Resource        ../_resources/keywords/Server.robot
+Resource        ../_resources/keywords/Browser.robot
+Resource        ../_resources/keywords/Lab.robot
+Resource        ../_resources/keywords/IPyForceGraph.robot
+Resource        ../_resources/keywords/Screenshots.robot
+Library         Collections
+Library         JupyterLibrary
+Library         OperatingSystem
+
+Force Tags      suite:scales
+
+
+*** Variables ***
+${SCREENS}      ${SCREENS ROOT}${/}api
+
+*** Test Cases ***
+{% for scale_type, scheme in {"ContinuousColor": "viridis", "OrdinalColor": "category10"}.items() %}
+{{ scale_type }} Can Update {{ graph_class }} Nodes
+    Scale Works As Expected  {{ graph_class }}  {{ scale_type }}  {{ scheme }}
+{% endfor %}
+
+
+*** Keywords ***
+Scale Works As Expected
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    ${screens} =    Set Variable    ${SCREENS}${/}${widget_class.lower()}_${scale_class}
+    Maybe Skip A Test    widget_class=${widget_class}   feature=${scale_class}
+    Set Screenshot Directory    ${screens}
+    Set Up Scale Example    ${widget_class}    ${scale_class}    ${scheme}
+    ${frame} =   Set Variable   css:${IPYFORCEGRAPH FRAME}
+    ${transparent} =    Get Element Screenshot Size    ${frame}  ${screens}    01-transparent.png
+    Add And Run JupyterLab Code Cell
+    ...    ns.color = scale
+    Wait For All Cells To Run
+    Sleep    1s
+    ${color} =   Get Element Screenshot Size    ${frame}    ${screens}    02-scale.png
+    Should Be True Or Screenshot    ${color} > ${transparent}  03-scale-bigger-than-transparent.png
+    [Teardown]    Clean Up Scale Example
+
+Set Up Scale Example
+    [Arguments]    ${widget_class}    ${scale_class}    ${scheme}
+    Set Tags    scale:${scale_class}    widget:${widget_class.lower()}
+    ${text} =    Get File    ${IPYFORCEGRAPH_FIXTURES}${/}api${/}Scales.py
+    ${text} =    Set Variable    ${text.replace("WIDGET_CLASS", "${widget_class}")}
+    ${text} =    Set Variable    ${text.replace("SCALE_CLASS", "${scale_class}")}
+    ${text} =    Set Variable    ${text.replace("SCHEME", "${scheme}")}
+    Launch A New JupyterLab Document
+    Set CodeMirror Value    .jp-CodeCell .CodeMirror    ${text.strip()}
+    Execute JupyterLab Command    Show Log Console
+    Execute JupyterLab Command    Run All Cells
+    Wait Until Force Graph Is Visible
+    Capture Page Screenshot    00-start.png
+
+Clean Up Scale Example
+    Capture Page Screenshot    99-fin.png
+    ${nb_dir} =    Get Jupyter Directory
+    Remove File    ${nb_dir}${/}Untitled.ipynb
+    Refresh File List
+    Try To Close All Tabs
diff --git a/atest/_resources/fixtures/api/Scales.py b/atest/_resources/fixtures/api/Scales.py
new file mode 100644
index 00000000..56ab2d55
--- /dev/null
+++ b/atest/_resources/fixtures/api/Scales.py
@@ -0,0 +1,13 @@
+from ipyforcegraph.graphs import WIDGET_CLASS
+from ipyforcegraph.behaviors.scales import SCALE_CLASS
+from ipyforcegraph.behaviors import NodeShapes
+
+ns = NodeShapes()
+fg = WIDGET_CLASS(behaviors=[ns])
+scale = SCALE_CLASS("id", scheme=SCALE_CLASS.Scheme.SCHEME)
+display(fg)
+fg.source.nodes = [{"id": 0}, {"id": 1}]
+fg.source.links = [{"source": 0, "target": 1}]
+transparent = "rgba(0,0,0,0.0)"
+fg.default_link_width = fg.default_node_size = 10
+fg.default_node_color = fg.default_link_color = fg.background_color = transparent
diff --git a/src/ipyforcegraph/tests/test_scales.py b/src/ipyforcegraph/tests/test_scales.py
new file mode 100644
index 00000000..bfad01c4
--- /dev/null
+++ b/src/ipyforcegraph/tests/test_scales.py
@@ -0,0 +1,43 @@
+"""Tests of basic scales."""
+
+# Copyright (c) 2023 ipyforcegraph contributors.
+# Distributed under the terms of the Modified BSD License.
+
+from typing import Any
+
+import pytest
+import traitlets as T
+
+import ipyforcegraph.behaviors.scales as S
+
+
+@pytest.mark.parametrize("name", [e.name for e in S.ContinuousColor.Scheme])
+def test_good_continuous_scale(name: str) -> None:
+    """Verify the known continuous scales are accepted."""
+    scheme = S.ContinuousColor.Scheme[name]
+    scale = S.ContinuousColor("value", scheme=scheme)
+    scale.scheme = scheme.value
+
+
+@pytest.mark.parametrize("scheme", [0, "false"])
+def test_bad_continuous_scale(scheme: Any) -> None:
+    """Verify rando continuous scales are caught."""
+    scale = S.ContinuousColor("value")
+    with pytest.raises(T.TraitError, match="expected any of"):
+        scale.scheme = scheme
+
+
+@pytest.mark.parametrize("name", [e.name for e in S.OrdinalColor.Scheme])
+def test_good_ordinal_scale(name: str) -> None:
+    """Verify the known ordinal scales are accepted."""
+    scheme = S.OrdinalColor.Scheme[name]
+    scale = S.OrdinalColor("value", scheme=scheme)
+    scale.scheme = scheme.value
+
+
+@pytest.mark.parametrize("scheme", [0, "false"])
+def test_bad_ordinal_scale(scheme: Any) -> None:
+    """Verify rando ordinal scales are caught."""
+    scale = S.OrdinalColor("value")
+    with pytest.raises(T.TraitError, match="expected any of"):
+        scale.scheme = scheme
diff --git a/src/ipyforcegraph/tests/test_widget_model_meta.py b/src/ipyforcegraph/tests/test_widget_model_meta.py
index 31b1f651..c7c5396b 100644
--- a/src/ipyforcegraph/tests/test_widget_model_meta.py
+++ b/src/ipyforcegraph/tests/test_widget_model_meta.py
@@ -9,7 +9,7 @@
 
 from ipyforcegraph import behaviors, graphs
 from ipyforcegraph._base import ForceBase
-from ipyforcegraph.behaviors import forces, shapes
+from ipyforcegraph.behaviors import forces, scales, shapes
 from ipyforcegraph.sources.dodo import DodoSource
 from ipyforcegraph.sources.widget import WidgetSource
 
@@ -29,6 +29,7 @@ def widget_subclasses() -> TSubclassSet:
     assert forces
     assert graphs
     assert shapes
+    assert scales
 
     subclasses: Set[Type] = SUBCLASS_BASES
     subclass_count = -1