Repository: jupyrdf/ipyradiant (language: python)

Issue:
Graph explorer widget
Adds the integrated graph explorer widget.

#### Test Procedure:
* Run the `GraphExplorer.ipynb` notebook
* Review the code
* checkout and `doit` if feeling thourough.

[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/zwelz3/ipyradiant/graph-explorer-widget?urlpath=lab/tree/index.ipynb)

Blocked by #61 
Closes #74 


Discussion / hints:

Fix patch:
diff --git a/.ci/environment.yml b/.ci/environment.yml
index 5a7f3fa..ee26015 100644
--- a/.ci/environment.yml
+++ b/.ci/environment.yml
@@ -2,8 +2,7 @@ name: ipyradiant-base
 
 channels:
   - https://conda.anaconda.org/conda-forge
-  - https://conda.anaconda.org/anaconda
-  - https://conda.anaconda.org/msys2
+  - nodefaults
 
 dependencies:
   - anaconda-project =0.8.4
@@ -12,3 +11,4 @@ dependencies:
   - pip
   - python >=3.7,<3.8
   - twine
+  - mamba
diff --git a/.ci/win.bat b/.ci/win.bat
index 0852276..f0076b8 100644
--- a/.ci/win.bat
+++ b/.ci/win.bat
@@ -1,7 +1,7 @@
 @echo on
 :: this is a nasty hack, and should not be needed, but the env isn't _quite_ right
-call deactivate
-call C:\Miniconda\envs\ipyradiant-base\Scripts\activate
+:: call deactivate
+:: call C:\Miniconda\envs\ipyradiant-base\Scripts\activate
 call doit -n4 %%*
 call doit %%* || goto :error
 
diff --git a/.github/.condarc b/.github/.condarc
new file mode 100644
index 0000000..d5cc1fb
--- /dev/null
+++ b/.github/.condarc
@@ -0,0 +1,14 @@
+add_pip_as_python_dependency: False
+aggressive_update_packages: []
+always_yes: True
+auto_update_conda: False
+default_channels: []
+local_repodata_ttl: 99999
+notify_outdated_conda: False
+remote_connect_timeout_secs: 600.0
+remote_max_retries: 10
+remote_read_timeout_secs: 600.0
+show_channel_urls: True
+show_sources: True
+unsatisfiable_hints_check_depth: 0
+use_only_tar_bz2: True
diff --git a/.github/workflows/ciV0.yml b/.github/workflows/ciV0.yml
index 7ea8ddd..05156da 100644
--- a/.github/workflows/ciV0.yml
+++ b/.github/workflows/ciV0.yml
@@ -10,6 +10,9 @@ env:
   PYTHONUNBUFFERED: 1
   SKIP_CONDA_PREFLIGHT: 1
   INSTALL_ARTIFACT: wheel
+  CONDA_EXE: mamba
+  FORGE_BASE: https://github.com/conda-forge/miniforge/releases/download/4.9.2-5/Mambaforge-4.9.2-5
+  CACHE_EPOCH: 0
 
 jobs:
   ci:
@@ -22,6 +25,13 @@ jobs:
           - ubuntu
           - macos
           - windows
+        include:
+          - os: ubuntu
+            miniforge: Linux-x86_64.sh
+          - os: macos
+            miniforge: MacOSX-x86_64.sh
+          - os: windows
+            miniforge: Windows-x86_64.exe
     steps:
       - name: configure line endings
         run: |
@@ -34,28 +44,30 @@ jobs:
         uses: actions/cache@v1
         with:
           path: ~/conda_pkgs_dir
-          key:
-            ${{ runner.os }}-conda-ci-${{ hashFiles('anaconda-project-lock.yml',
-            '.ci/environment.yml') }}
+          key: |
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-ci-${{ hashFiles('anaconda-project-lock.yml', '.ci/environment.yml') }}
           restore-keys: |
-            ${{ runner.os }}-conda-ci-
-            ${{ runner.os }}-conda-
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-ci-
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-
 
       - name: cache (yarn)
         uses: actions/cache@v1
         with:
           path: .yarn-packages
-          key: yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+          key: |
+            ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
           restore-keys: |
-            yarn-${{ runner.os }}-
-            yarn-
+            ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-
+            ${{ env.CACHE_EPOCH }}-yarn-
 
       - name: env (conda)
         uses: conda-incubator/setup-miniconda@v2
         with:
           activate-environment: ipyradiant-base
           auto-activate-base: false
+          condarc-file: .github/.condarc
           environment-file: .ci/environment.yml
+          installer-url: ${{ env.FORGE_BASE }}-${{ matrix.miniforge }}
           show-channel-urls: true
           use-only-tar-bz2: true
 
@@ -93,6 +105,13 @@ jobs:
           - ubuntu
           - macos
           - windows
+        include:
+          - os: ubuntu
+            miniforge: Linux-x86_64.sh
+          - os: macos
+            miniforge: MacOSX-x86_64.sh
+          - os: windows
+            miniforge: Windows-x86_64.exe
     steps:
       - name: configure line endings
         run: |
@@ -105,26 +124,30 @@ jobs:
         uses: actions/cache@v1
         with:
           path: ~/conda_pkgs_dir
-          key: ${{ runner.os }}-conda-ui-${{ hashFiles('anaconda-project-lock.yml') }}
+          key: |
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-ui-${{ hashFiles('anaconda-project-lock.yml') }}
           restore-keys: |
-            ${{ runner.os }}-conda-ui-
-            ${{ runner.os }}-conda-
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-ui-
+            ${{ env.CACHE_EPOCH }}-${{ runner.os }}-conda-
 
       - name: cache (yarn)
         uses: actions/cache@v1
         with:
           path: .yarn-packages
-          key: yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
+          key: |
+            ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-${{ hashFiles('yarn.lock') }}
           restore-keys: |
-            yarn-${{ runner.os }}-
-            yarn-
+            ${{ env.CACHE_EPOCH }}-yarn-${{ runner.os }}-
+            ${{ env.CACHE_EPOCH }}-yarn-
 
       - name: env (conda)
         uses: conda-incubator/setup-miniconda@v2
         with:
           activate-environment: ipyradiant-base
           auto-activate-base: false
+          condarc-file: .github/.condarc
           environment-file: .ci/environment.yml
+          installer-url: ${{ env.FORGE_BASE }}-${{ matrix.miniforge }}
           show-channel-urls: true
           use-only-tar-bz2: true
 
diff --git a/.isort.cfg b/.isort.cfg
deleted file mode 100644
index ba2778d..0000000
--- a/.isort.cfg
+++ /dev/null
@@ -1,6 +0,0 @@
-[settings]
-multi_line_output=3
-include_trailing_comma=True
-force_grid_wrap=0
-use_parentheses=True
-line_length=88
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c47b3c5..59fc1b2 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,27 +16,33 @@
 >
 > `doit` will cowardly refuse to do anything if some of the above are not met
 
-- install [Miniconda](https://docs.conda.io/en/latest/miniconda.html) (Python 3, 64-bit)
+- install [Mambaforge](https://github.com/conda-forge/miniforge/releases)
 - install `anaconda-project` and `doit` into the `base` env
 
 ```bat
-conda install anaconda-project=0.8.4 doit=0.32
+mamba install -c conda-forge anaconda-project=0.8.4 doit=0.32
 ```
 
 or, use the same base environment as CI:
 
 ```bat
 :: windows
-conda env update --file .ci\environment.yml
+mamba env update --file .ci\environment.yml
 c:\mc3\envs\ipyradiant-base\Scripts\activate
 ```
 
 ```bash
 # unix
-conda env update --file .ci/environment.yml
+mamba env update --file .ci/environment.yml
 source ~/mc3/envs/ipyradiant-base/bin/activate
 ```
 
+## See What You Can do(it)
+
+```bash
+doit list --all --status
+```
+
 ## Get To a Running Lab
 
 ```bash
@@ -84,3 +90,30 @@ anaconda-project run --env-spec build twine upload dist/ipyradiant-*
 - Complete `conda-forge` tasks
 
 [radiance-si-units]: https://en.wikipedia.org/wiki/Radiance#SI_radiometry_units
+
+## Updating environments
+
+After changing any `env_spec` in `anaconda-project.yml` (and/or `environment.yml`), it
+is recommended to use `mamba` for the rather hefty re-solve of all the environments.
+
+```bash
+# On Unix
+export CONDA_EXE=mamba
+export CONDARC=.github/.condarc
+anaconda-project update -n dev
+anaconda-project update -n build
+anaconda-project update -n qa
+doit lint:prettier
+```
+
+Or...
+
+```bat
+::on windows
+set CONDA_EXE=mamba
+set CONDARC=.github\.condarc
+anaconda-project update -n dev
+anaconda-project update -n build
+anaconda-project update -n qa
+doit lint:prettier
+```
diff --git a/_scripts/nblint.py b/_scripts/nblint.py
index b2a4c78..5231a44 100644
--- a/_scripts/nblint.py
+++ b/_scripts/nblint.py
@@ -3,8 +3,6 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-
-import json
 import shutil
 import subprocess
 import sys
@@ -14,6 +12,7 @@
 import black
 import isort
 import nbformat
+from isort.api import sort_code_string
 
 from . import project as P
 
@@ -21,7 +20,7 @@
 
 NB_METADATA_KEYS = ["kernelspec", "language_info"]
 
-ENC = {"encoding": "utf-8"}
+ISORT_CONFIG = isort.settings.Config(settings_path=P.SETUP_CFG)
 
 
 def blacken(source):
@@ -71,7 +70,7 @@ def nblint_one(nb_node):
                 continue
             if source.startswith("%"):
                 continue
-            new = isort.SortImports(file_contents=source).output
+            new = sort_code_string(source, config=ISORT_CONFIG)
             new = blacken(new).rstrip()
             if new != source:
                 cell["source"] = new.splitlines(True)
@@ -93,39 +92,24 @@ def nb_hash(nb_text):
 
 def nblint(nb_paths):
     """lint a number of notebook paths"""
-    nb_hashes = {}
-
-    if P.NBLINT_HASHES.exists():
-        nb_hashes = json.loads(P.NBLINT_HASHES.read_text(**ENC))
-
     len_paths = len(nb_paths)
 
     for i, nb_path in enumerate(nb_paths):
-        hash_key = f"{nb_path}"
-        log_hash = nb_hashes.get(hash_key)
-        nb_text = nb_path.read_text(**ENC)
+        nb_text = nb_path.read_text(encoding="utf-8")
         pre_hash = nb_hash(nb_text)
 
-        print(f"[{i + 1} of {len_paths}] {nb_path}")
-        if log_hash == pre_hash:
-            continue
+        if len_paths > 1:
+            print(f"[{i + 1} of {len_paths}] {nb_path}", flush=True)
 
         nb_node = nblint_one(nbformat.reads(nb_text, 4))
 
-        with nb_path.open("w") as fpt:
+        with nb_path.open("w", encoding="utf-8") as fpt:
             nbformat.write(nb_node, fpt)
 
-        post_hash = nb_hash(nb_path.read_text(**ENC))
+        post_hash = nb_hash(nb_path.read_text(encoding="utf-8"))
 
         if post_hash != pre_hash:
-            print("\tformatted")
-        else:
-            print("\tno change")
-
-        nb_hashes[hash_key] = post_hash
-
-    P.NBLINT_HASHES.parent.mkdir(exist_ok=True, parents=True)
-    P.NBLINT_HASHES.write_text(json.dumps(nb_hashes, indent=2, sort_keys=True))
+            print(f"\t{nb_path.name} formatted")
 
     return 0
 
diff --git a/_scripts/project.py b/_scripts/project.py
index f292483..f92cd05 100644
--- a/_scripts/project.py
+++ b/_scripts/project.py
@@ -44,6 +44,7 @@
 PROJ_LOCK = ROOT / "anaconda-project-lock.yml"
 VENDOR = ROOT / "vendor"
 CHANGELOG = ROOT / "CHANGELOG.md"
+CONDARC = CI / ".condarc"
 
 # tools
 PY = ["python"]
@@ -118,12 +119,11 @@ def _not_checkpoint(paths):
 OK_PREFLIGHT_LAB = BUILD / "preflight.lab.ok"
 OK_PREFLIGHT_RELEASE = BUILD / "preflight.release.ok"
 HTML_COV_INDEX = BUILD / "htmlcov/index.html"
-NBLINT_HASHES = BUILD / "nblint.hashes"
 OK_BLACK = BUILD / "black.ok"
 OK_FLAKE8 = BUILD / "flake8.ok"
 OK_LINT = BUILD / "lint.ok"
 OK_PYFLAKES = BUILD / "pyflakes.ok"
-OK_NBLINT = BUILD / "nblint.ok"
+OK_NBLINT = BUILD / "nblint.ok.d"
 OK_PIP_INSTALL = BUILD / "pip_install.ok"
 OK_PRETTIER = BUILD / "prettier.ok"
 
diff --git a/anaconda-project-lock.yml b/anaconda-project-lock.yml
index 791a330..df9c3ba 100644
--- a/anaconda-project-lock.yml
+++ b/anaconda-project-lock.yml
@@ -19,343 +19,440 @@ env_specs:
     locked: false
   dev:
     locked: true
-    env_spec_hash: ced8325864ed2b0f4c3b41962ea34c651e8791d7
+    env_spec_hash: e1b58f93426c55365bde30d4c55de491b508c19a
     platforms:
       - linux-64
       - osx-64
       - win-64
     packages:
       all:
-        - attrs=20.2.0=pyh9f0ad1d_0
+        - appdirs=1.4.4=pyh9f0ad1d_0
+        - async_generator=1.10=py_0
+        - attrs=20.3.0=pyhd3deb0d_0
         - backcall=0.2.0=pyh9f0ad1d_0
         - backports.functools_lru_cache=1.6.1=py_0
         - backports=1.0=py_2
-        - bleach=3.1.5=pyh9f0ad1d_0
-        - ca-certificates=2020.6.20=hecda079_0
-        - certifi=2020.6.20=py37hc8dfbb8_0
-        - chardet=3.0.4=py37hc8dfbb8_1006
+        - bleach=3.2.1=pyh9f0ad1d_0
+        - cachetools=4.1.1=py_0
         - click=7.1.2=pyh9f0ad1d_0
         - cloudpickle=1.6.0=py_0
-        - colorcet=2.0.1=py_0
+        - colorcet=2.0.6=pyhd8ed1ab_0
         - cycler=0.10.0=py_2
-        - dask-core=2.25.0=py_0
-        - dask=2.25.0=py_0
-        - datashader=0.11.1=pyh9f0ad1d_0
+        - dask-core=2021.1.0=pyhd8ed1ab_0
+        - dask=2021.1.0=pyhd8ed1ab_0
+        - datashader=0.12.0=pyhd3deb0d_0
         - datashape=0.5.4=py_1
         - decorator=4.4.2=py_0
         - defusedxml=0.6.0=py_0
-        - distributed=2.25.0=py37hc8dfbb8_0
-        - entrypoints=0.3=py37hc8dfbb8_1001
-        - fsspec=0.8.0=py_0
+        - frozendict=1.2=pyh9f0ad1d_3
+        - fsspec=0.8.5=pyhd8ed1ab_0
         - heapdict=1.0.1=py_0
-        - holoviews=1.13.3=pyh9f0ad1d_0
+        - holoviews=1.14.1=pyhd3deb0d_0
         - html5lib=1.1=pyh9f0ad1d_0
-        - hvplot=0.6.0=pyh9f0ad1d_0
+        - hvplot=0.7.0=pyhd3deb0d_0
         - idna=2.10=pyh9f0ad1d_0
         - imageio=2.9.0=py_0
-        - importlib-metadata=1.7.0=py37hc8dfbb8_0
-        - importlib_metadata=1.7.0=0
-        - importnb=0.6.2=py37hc8dfbb8_0
-        - iniconfig=1.0.1=pyh9f0ad1d_0
-        - ipycytoscape=1.0.4=py_0
-        - ipython=7.18.1=py37hc6149b9_0
+        - importlib_metadata=3.4.0=hd8ed1ab_0
+        - importnb=0.7.0=pyhd8ed1ab_0
+        - iniconfig=1.1.1=pyh9f0ad1d_0
+        - ipycytoscape=1.0.4=pyhd8ed1ab_1
         - ipython_genutils=0.2.0=py_1
-        - ipywidgets=7.5.1=pyh9f0ad1d_1
+        - ipywidgets=7.6.3=pyhd3deb0d_0
         - isodate=0.6.0=py_1
-        - jedi=0.17.2=py37hc8dfbb8_0
         - jinja2=2.11.2=pyh9f0ad1d_0
-        - json5=0.9.4=pyh9f0ad1d_0
-        - jsonschema=3.2.0=py37hc8dfbb8_1
-        - jupyter_client=6.1.7=py_0
-        - jupyter_core=4.6.3=py37hc8dfbb8_1
+        - json5=0.9.5=pyh9f0ad1d_0
+        - jupyter_client=6.1.11=pyhd8ed1ab_1
         - jupyterlab=2.2.5=py_0
+        - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
         - jupyterlab_server=1.2.0=py_0
-        - keepalive=0.5=py_1
+        - jupyterlab_widgets=1.0.0=pyhd8ed1ab_1
         - locket=0.2.0=py_2
-        - markdown=3.2.2=py_0
-        - more-itertools=8.5.0=py_0
+        - markdown=3.3.3=pyh9f0ad1d_0
+        - more-itertools=8.6.0=pyhd8ed1ab_0
         - multipledispatch=0.6.0=py_0
-        - nbconvert=5.6.1=py37hc8dfbb8_1
-        - nbformat=5.0.7=py_0
+        - nbclient=0.5.1=py_0
+        - nbformat=5.1.2=pyhd8ed1ab_1
+        - nest-asyncio=1.4.3=pyhd8ed1ab_0
         - networkx=2.5=py_0
-        - notebook=6.1.3=py37hc8dfbb8_0
-        - olefile=0.46=py_0
+        - olefile=0.46=pyh9f0ad1d_1
         - owlrl=5.2.1=py_0
-        - packaging=20.4=pyh9f0ad1d_0
+        - packaging=20.8=pyhd3deb0d_0
         - pandocfilters=1.4.2=py_1
-        - panel=0.9.7=py_0
-        - param=1.9.3=py_0
-        - parso=0.7.1=pyh9f0ad1d_0
+        - panel=0.10.3=pyhd8ed1ab_0
+        - param=1.10.1=pyhd3deb0d_0
         - partd=1.1.0=py_0
-        - pickleshare=0.7.5=py37hc8dfbb8_1001
-        - pip=20.2.3=py_0
-        - pluggy=0.13.1=py37hc8dfbb8_2
-        - prometheus_client=0.8.0=pyh9f0ad1d_0
-        - prompt-toolkit=3.0.7=py_0
-        - py=1.9.0=pyh9f0ad1d_0
+        - pip=20.3.3=pyhd8ed1ab_0
+        - pooch=1.3.0=pyhd8ed1ab_0
+        - prometheus_client=0.9.0=pyhd3deb0d_0
+        - prompt-toolkit=3.0.10=pyha770c72_0
+        - py=1.10.0=pyhd3deb0d_0
         - pycparser=2.20=pyh9f0ad1d_2
         - pyct-core=0.4.6=py_0
         - pyct=0.4.6=py_0
-        - pygments=2.6.1=py_0
-        - pyld=1.0.4=py_0
-        - pyopenssl=19.1.0=py_1
+        - pygments=2.7.4=pyhd8ed1ab_0
+        - pyld=2.0.3=pyh9f0ad1d_0
+        - pyopenssl=20.0.1=pyhd8ed1ab_0
         - pyparsing=2.4.7=pyh9f0ad1d_0
-        - pyshacl=0.13.1=py_0
-        - pysocks=1.7.1=py37hc8dfbb8_1
-        - pytest-cov=2.10.1=pyh9f0ad1d_0
-        - pytest=6.0.1=py37hc8dfbb8_0
+        - pyshacl=0.14.2=pyhd8ed1ab_0
+        - pytest-cov=2.11.1=pyh44b312d_0
         - python-dateutil=2.8.1=py_0
         - python_abi=3.7=1_cp37m
-        - pytz=2020.1=pyh9f0ad1d_0
+        - pytz=2020.5=pyhd8ed1ab_0
         - pyviz_comms=0.7.6=pyh9f0ad1d_0
-        - qgrid=1.3.1=py37hc8dfbb8_0
-        - rdflib-jsonld=0.5.0=py37hc8dfbb8_0
-        - rdflib=5.0.0=py37hc8dfbb8_2
-        - requests=2.24.0=pyh9f0ad1d_0
+        - qgrid=1.3.1=py37hc8dfbb8_1
+        - requests=2.25.1=pyhd3deb0d_0
         - requests_cache=0.4.13=py_0
         - send2trash=1.5.0=py_0
-        - setuptools=49.6.0=py37hc8dfbb8_0
         - six=1.15.0=pyh9f0ad1d_0
-        - sortedcontainers=2.2.2=pyh9f0ad1d_0
-        - sparqlwrapper=1.8.5=py37hc8dfbb8_1003
-        - spectate=0.4.1=pyh9f0ad1d_0
+        - sortedcontainers=2.3.0=pyhd8ed1ab_0
         - tblib=1.6.0=py_0
-        - terminado=0.8.3=py37hc8dfbb8_1
         - testpath=0.4.4=py_0
-        - toml=0.10.1=pyh9f0ad1d_0
-        - toolz=0.10.0=py_0
-        - tqdm=4.48.2=pyh9f0ad1d_0
-        - traitlets=4.3.3=py37hc8dfbb8_1
-        - traittypes=0.2.1=py_1
-        - typing_extensions=3.7.4.2=py_0
-        - urllib3=1.25.10=py_0
-        - wcwidth=0.2.5=pyh9f0ad1d_1
+        - tifffile=2021.1.14=pyhd8ed1ab_0
+        - toml=0.10.2=pyhd8ed1ab_0
+        - toolz=0.11.1=py_0
+        - tqdm=4.56.0=pyhd8ed1ab_0
+        - traitlets=5.0.5=py_0
+        - traittypes=0.2.1=pyh9f0ad1d_2
+        - typing_extensions=3.7.4.3=py_0
+        - urllib3=1.26.2=pyhd8ed1ab_0
+        - wcwidth=0.2.5=pyh9f0ad1d_2
         - webencodings=0.5.1=py_1
-        - wheel=0.35.1=pyh9f0ad1d_0
-        - widgetsnbextension=3.5.1=py37hc8dfbb8_1
-        - xarray=0.16.0=py_0
+        - wheel=0.36.2=pyhd3deb0d_0
+        - xarray=0.16.2=pyhd8ed1ab_0
         - zict=2.0.0=py_0
-        - zipp=3.1.0=py_0
+        - zipp=3.4.0=py_0
       unix:
-        - bokeh=2.2.1=py37hc8dfbb8_0
-        - ipykernel=5.3.4=py37h43977f1_0
-        - libblas=3.8.0=17_openblas
-        - libcblas=3.8.0=17_openblas
-        - liblapack=3.8.0=17_openblas
-        - pexpect=4.8.0=py37hc8dfbb8_1
-        - ptyprocess=0.6.0=py_1001
-        - tifffile=2020.9.3=py_0
+        - libblas=3.9.0=7_openblas
+        - libcblas=3.9.0=7_openblas
+        - liblapack=3.9.0=7_openblas
+        - ptyprocess=0.7.0=pyhd3deb0d_0
       linux-64:
         - _libgcc_mutex=0.1=conda_forge
         - _openmp_mutex=4.5=1_gnu
-        - argon2-cffi=20.1.0=py37h8f50634_1
-        - blosc=1.20.1=he1b5a44_0
-        - brotli=1.0.9=he1b5a44_0
-        - brotlipy=0.7.0=py37h8f50634_1000
+        - argon2-cffi=20.1.0=py37h8f50634_2
+        - blosc=1.21.0=h9c3ff4c_0
+        - bokeh=2.2.3=py37hc8dfbb8_0
+        - brotli=1.0.9=h9c3ff4c_4
+        - brotlipy=0.7.0=py37hb5d75c8_1001
         - brunsli=0.1=he1b5a44_0
-        - bzip2=1.0.8=h516909a_3
-        - cffi=1.14.1=py37h2b28604_0
-        - charls=2.1.0=he1b5a44_2
-        - coverage=5.2.1=py37h8f50634_0
-        - cryptography=3.1=py37hb09aad4_0
-        - cytoolz=0.10.1=py37h516909a_0
-        - freetype=2.10.2=he06d7ca_0
+        - bzip2=1.0.8=h7f98852_4
+        - ca-certificates=2020.12.5=ha878542_0
+        - certifi=2020.12.5=py37h89c1867_1
+        - cffi=1.14.4=py37hc58025e_1
+        - chardet=4.0.0=py37h89c1867_1
+        - charls=2.2.0=h9c3ff4c_0
+        - coverage=5.3.1=py37h5e8e339_1
+        - cryptography=3.3.1=py37h7f0c10b_1
+        - cytoolz=0.11.0=py37h8f50634_1
+        - dataclasses=0.7=py37_0
+        - distributed=2021.1.0=py37h89c1867_1
+        - entrypoints=0.3=py37hc8dfbb8_1002
+        - freetype=2.10.4=h0708190_1
         - giflib=5.2.1=h516909a_2
-        - icu=64.2=he1b5a44_1
-        - imagecodecs=2020.5.30=py37hda6ee5b_2
+        - icu=68.1=h58526e2_0
+        - imagecodecs=2021.1.11=py37h95c7a1b_1
+        - importlib-metadata=3.4.0=py37h89c1867_0
+        - importlib_resources=5.1.0=py37h89c1867_0
+        - ipykernel=5.4.2=py37h888b3d9_0
+        - ipython=7.19.0=py37h888b3d9_2
+        - jedi=0.17.2=py37hc8dfbb8_1
         - jpeg=9d=h516909a_0
+        - jsonschema=3.2.0=py37hc8dfbb8_1
+        - jupyter_core=4.7.0=py37h89c1867_0
         - jxrlib=1.1=h516909a_2
-        - kiwisolver=1.2.0=py37h99015e2_0
-        - lcms2=2.11=hbd6801e_0
-        - ld_impl_linux-64=2.34=hc38a660_9
-        - lerc=2.2=he1b5a44_0
+        - keepalive=0.5=py37h89c1867_5
+        - kiwisolver=1.3.1=py37h2527ec5_1
+        - lcms2=2.11=hcbb858e_1
+        - ld_impl_linux-64=2.35.1=hed1e6ac_1
+        - lerc=2.2.1=h9c3ff4c_0
         - libaec=1.0.4=he1b5a44_1
-        - libffi=3.2.1=he1b5a44_1007
-        - libgcc-ng=9.3.0=h24d8f2e_16
-        - libgfortran-ng=7.5.0=hdf63c60_16
-        - libgomp=9.3.0=h24d8f2e_16
+        - libdeflate=1.7=h7f98852_5
+        - libffi=3.3=h58526e2_2
+        - libgcc-ng=9.3.0=h2828fa1_18
+        - libgfortran-ng=9.3.0=hff62375_18
+        - libgfortran5=9.3.0=hff62375_18
+        - libgomp=9.3.0=h2828fa1_18
+        - libiconv=1.16=h516909a_0
         - libllvm10=10.0.1=he513fc3_3
-        - libopenblas=0.3.10=pthreads_hb3c22a3_4
+        - libopenblas=0.3.12=pthreads_h4812303_1
         - libpng=1.6.37=hed695b0_2
-        - libsodium=1.0.18=h516909a_0
-        - libstdcxx-ng=9.3.0=hdf63c60_16
-        - libtiff=4.1.0=hc7e4089_6
-        - libuv=1.39.0=h516909a_0
+        - libsodium=1.0.18=h516909a_1
+        - libstdcxx-ng=9.3.0=h6de172a_18
+        - libtiff=4.2.0=hdc55705_0
+        - libuv=1.40.0=hd18ef5c_0
         - libwebp-base=1.1.0=h516909a_3
+        - libxml2=2.9.10=h72842e0_3
+        - libxslt=1.1.33=h15afd5d_2
         - libzopfli=1.0.3=he1b5a44_0
-        - llvmlite=0.34.0=py37h5202443_1
-        - lz4-c=1.9.2=he1b5a44_3
-        - markupsafe=1.1.1=py37h8f50634_1
-        - matplotlib-base=3.3.1=py37hd478181_1
-        - mistune=0.8.4=py37h8f50634_1001
-        - msgpack-python=1.0.0=py37h99015e2_1
-        - ncurses=6.2=he1b5a44_1
-        - nodejs=12.18.3=h67efad7_0
-        - numba=0.51.2=py37h9fdb41a_0
-        - numpy=1.19.1=py37h7ea13bd_2
-        - openjpeg=2.3.1=h981e76c_3
-        - openssl=1.1.1g=h516909a_1
-        - pandas=1.1.2=py37h3340039_0
-        - pandoc=2.10.1=h516909a_0
-        - pillow=7.2.0=py37h718be6c_1
-        - psutil=5.7.2=py37h8f50634_0
-        - pyrsistent=0.16.0=py37h8f50634_0
-        - python=3.7.8=h6f2ec95_1_cpython
-        - pywavelets=1.1.1=py37h161383b_2
-        - pyyaml=5.3.1=py37h8f50634_0
-        - pyzmq=19.0.2=py37hac76be4_0
+        - llvmlite=0.35.0=py37h9d7f4d0_1
+        - lxml=4.6.2=py37h77fd288_1
+        - lz4-c=1.9.3=h9c3ff4c_0
+        - markupsafe=1.1.1=py37h5e8e339_3
+        - matplotlib-base=3.3.3=py37h4f6019d_0
+        - mistune=0.8.4=py37h5e8e339_1003
+        - msgpack-python=1.0.2=py37h2527ec5_1
+        - nbconvert=6.0.7=py37h89c1867_3
+        - ncurses=6.2=h58526e2_4
+        - nodejs=12.19.0=hfa01f41_2
+        - notebook=6.2.0=py37h89c1867_0
+        - numba=0.52.0=py37hdc94413_0
+        - numpy=1.19.5=py37haa41c4c_1
+        - openjpeg=2.4.0=hf7af979_0
+        - openssl=1.1.1i=h7f98852_0
+        - pandas=1.2.1=py37hdc94413_0
+        - pandoc=2.11.3.2=h7f98852_0
+        - parso=0.7.1=pyh9f0ad1d_0
+        - pexpect=4.8.0=py37hc8dfbb8_1
+        - pickleshare=0.7.5=py37hc8dfbb8_1002
+        - pillow=8.1.0=py37he6b4880_1
+        - pluggy=0.13.1=py37h89c1867_4
+        - psutil=5.8.0=py37h5e8e339_1
+        - pyrsistent=0.17.3=py37h5e8e339_2
+        - pysocks=1.7.1=py37h89c1867_3
+        - pytest=6.2.1=py37h89c1867_1
+        - python=3.7.9=hffdb5ce_0_cpython
+        - pywavelets=1.1.1=py37h161383b_3
+        - pyyaml=5.3.1=py37h5e8e339_2
+        - pyzmq=21.0.1=py37h499b945_0
+        - rdflib-jsonld=0.5.0=py37hc8dfbb8_2
+        - rdflib=5.0.0=py37hc8dfbb8_3
         - readline=8.0=he28a2e2_2
-        - scikit-image=0.17.2=py37h9fdb41a_2
-        - scipy=1.5.2=py37hb14ef9d_0
+        - scikit-image=0.18.1=py37hdc94413_0
+        - scipy=1.6.0=py37h14a347d_0
+        - setuptools=49.6.0=py37h89c1867_3
         - snappy=1.1.8=he1b5a44_3
-        - sqlite=3.33.0=h4cf870e_0
-        - tk=8.6.10=hed695b0_0
-        - tornado=6.0.4=py37h8f50634_1
+        - sparqlwrapper=1.8.5=py37h89c1867_1005
+        - spectate=1.0.0=py37h89c1867_1
+        - sqlite=3.34.0=h74cdb3f_0
+        - terminado=0.9.2=py37h89c1867_0
+        - tk=8.6.10=hed695b0_1
+        - tornado=6.1=py37h5e8e339_1
+        - widgetsnbextension=3.5.1=py37hc8dfbb8_4
         - xz=5.2.5=h516909a_1
         - yaml=0.2.5=h516909a_0
-        - zeromq=4.3.2=he1b5a44_3
-        - zfp=0.5.5=he1b5a44_1
-        - zlib=1.2.11=h516909a_1009
-        - zstd=1.4.5=h6597ccf_2
+        - zeromq=4.3.3=h58526e2_3
+        - zfp=0.5.5=he1b5a44_4
+        - zlib=1.2.11=h516909a_1010
+        - zstd=1.4.8=ha95c52a_1
       osx-64:
-        - appnope=0.1.0=py37hc8dfbb8_1001
-        - argon2-cffi=20.1.0=py37h60d8a13_1
-        - blosc=1.20.1=hb1e8313_0
-        - brotli=1.0.9=hb1e8313_0
-        - brotlipy=0.7.0=py37h9bfed18_1000
-        - brunsli=0.1=hb1e8313_0
-        - bzip2=1.0.8=haf1e3a3_3
-        - cffi=1.14.1=py37hf5b7abd_0
-        - charls=2.1.0=h4a8c4bd_2
-        - coverage=5.2.1=py37h60d8a13_0
-        - cryptography=3.1=py37h94e4008_0
-        - cytoolz=0.10.1=py37h0b31af3_0
-        - freetype=2.10.2=h8da9a1a_0
-        - giflib=5.2.1=h0b31af3_2
-        - icu=64.2=h6de7cb9_1
-        - imagecodecs=2020.5.30=py37h64a549b_2
-        - jpeg=9d=h0b31af3_0
-        - jxrlib=1.1=h0b31af3_2
-        - kiwisolver=1.2.0=py37ha1cc60f_0
-        - lcms2=2.11=h174193d_0
-        - lerc=2.2=hb1e8313_0
-        - libaec=1.0.4=h4a8c4bd_1
-        - libcxx=10.0.1=h5f48129_0
-        - libffi=3.2.1=hb1e8313_1007
-        - libgfortran4=7.5.0=h1565451_3
-        - libgfortran=4.0.0=3
+        - appnope=0.1.2=py37hf985489_1
+        - argon2-cffi=20.1.0=py37hf967b71_2
+        - blosc=1.21.0=h046ec9c_0
+        - bokeh=2.2.3=py37hf985489_0
+        - brotli=1.0.9=h046ec9c_4
+        - brotlipy=0.7.0=py37hf967b71_1001
+        - brunsli=0.1=h046ec9c_0
+        - bzip2=1.0.8=hc929b4f_4
+        - ca-certificates=2020.12.5=h033912b_0
+        - certifi=2020.12.5=py37hf985489_1
+        - cffi=1.14.4=py37hc5b2277_1
+        - chardet=4.0.0=py37hf985489_1
+        - charls=2.2.0=h046ec9c_0
+        - coverage=5.3.1=py37hf967b71_1
+        - cryptography=3.3.1=py37haf76d9e_1
+        - cytoolz=0.11.0=py37he6e4e01_1
+        - dataclasses=0.7=pyhb2cacf7_7
+        - distributed=2021.1.0=py37hf985489_1
+        - entrypoints=0.3=pyhd8ed1ab_1003
+        - freetype=2.10.4=h4cff582_1
+        - giflib=5.2.1=hbcb3906_2
+        - icu=68.1=h74dc148_0
+        - imagecodecs=2021.1.11=py37h37c44b6_1
+        - importlib-metadata=3.4.0=py37hf985489_0
+        - importlib_resources=5.1.0=py37hf985489_0
+        - ipykernel=5.4.2=py37he01cfaa_0
+        - ipython=7.18.1=py37hc6149b9_1
+        - jedi=0.18.0=py37hf985489_2
+        - jpeg=9d=hbcb3906_0
+        - jsonschema=3.2.0=py_2
+        - jupyter_core=4.7.0=py37hf985489_0
+        - jxrlib=1.1=h35c211d_2
+        - keepalive=0.5=py37hf985489_5
+        - kiwisolver=1.3.1=py37h70f7d40_1
+        - lcms2=2.11=h11f7e16_1
+        - lerc=2.2.1=h046ec9c_0
+        - libaec=1.0.4=h046ec9c_1
+        - libcxx=11.0.0=h4c3b8ed_1
+        - libdeflate=1.7=h35c211d_5
+        - libffi=3.3=h046ec9c_2
+        - libgfortran5=9.3.0=h6c81a4c_16
+        - libgfortran=5.0.0=9_3_0_h6c81a4c_16
+        - libiconv=1.16=haf1e3a3_0
         - libllvm10=10.0.1=h009f743_3
-        - libopenblas=0.3.10=openmp_h63d9170_4
-        - libpng=1.6.37=hb0a8c7a_2
-        - libsodium=1.0.18=h01d97ff_0
-        - libtiff=4.1.0=h2ae36a8_6
-        - libuv=1.39.0=haf1e3a3_0
-        - libwebp-base=1.1.0=h0b31af3_3
-        - libzopfli=1.0.3=h4a8c4bd_0
-        - llvm-openmp=10.0.1=h28b9765_0
-        - llvmlite=0.34.0=py37h3986384_1
-        - lz4-c=1.9.2=hb1e8313_3
-        - markupsafe=1.1.1=py37h9bfed18_1
-        - matplotlib-base=3.3.1=py37h886f89f_1
-        - mistune=0.8.4=py37h9bfed18_1001
-        - msgpack-python=1.0.0=py37ha1cc60f_1
-        - ncurses=6.2=hb1e8313_1
-        - nodejs=12.18.3=h1293169_0
-        - numba=0.51.2=py37h6d0141a_0
-        - numpy=1.19.1=py37h1efc2f6_2
-        - openjpeg=2.3.1=h254dc36_3
-        - openssl=1.1.1g=haf1e3a3_1
-        - pandas=1.1.2=py37hdadc0f0_0
-        - pandoc=2.10.1=haf1e3a3_0
-        - pillow=7.2.0=py37hfd78ece_1
-        - psutil=5.7.2=py37h60d8a13_0
-        - pyrsistent=0.16.0=py37h9bfed18_0
-        - python=3.7.8=hc9dea61_1_cpython
-        - pywavelets=1.1.1=py37h57c32b8_2
-        - pyyaml=5.3.1=py37h9bfed18_0
-        - pyzmq=19.0.2=py37hf1e22d8_0
+        - libopenblas=0.3.12=openmp_h54245bb_1
+        - libpng=1.6.37=h7cec526_2
+        - libsodium=1.0.18=hbcb3906_1
+        - libtiff=4.2.0=h355d032_0
+        - libuv=1.40.0=h35c211d_0
+        - libwebp-base=1.1.0=hbcb3906_3
+        - libxml2=2.9.10=h802ca4f_3
+        - libxslt=1.1.33=h5739fc3_2
+        - libzopfli=1.0.3=h046ec9c_0
+        - llvm-openmp=11.0.1=h7c73e74_0
+        - llvmlite=0.35.0=py37hd32b0aa_1
+        - lxml=4.6.2=py37he94f95d_1
+        - lz4-c=1.9.3=h046ec9c_0
+        - markupsafe=1.1.1=py37hf967b71_3
+        - matplotlib-base=3.3.3=py37hef07623_0
+        - mistune=0.8.4=py37hf967b71_1003
+        - msgpack-python=1.0.2=py37h70f7d40_1
+        - nbconvert=6.0.7=py37hf985489_3
+        - ncurses=6.2=h2e338ed_4
+        - nodejs=12.19.0=h49b9f75_2
+        - notebook=6.2.0=py37hf985489_0
+        - numba=0.52.0=py37h010c265_0
+        - numpy=1.19.5=py37hec87de9_1
+        - openjpeg=2.4.0=h6cbf5cd_0
+        - openssl=1.1.1i=h35c211d_0
+        - pandas=1.2.1=py37h010c265_0
+        - pandoc=2.11.3.2=h35c211d_0
+        - parso=0.8.1=pyhd8ed1ab_0
+        - pexpect=4.8.0=pyh9f0ad1d_2
+        - pickleshare=0.7.5=py_1003
+        - pillow=8.1.0=py37h40a97b9_1
+        - pluggy=0.13.1=py37hf985489_4
+        - psutil=5.8.0=py37hf967b71_1
+        - pyrsistent=0.17.3=py37hf967b71_2
+        - pysocks=1.7.1=py37hf985489_3
+        - pytest=6.2.1=py37hf985489_1
+        - python=3.7.9=h6c3b2c9_0_cpython
+        - pywavelets=1.1.1=py37h37391d0_3
+        - pyyaml=5.3.1=py37hf967b71_2
+        - pyzmq=21.0.1=py37h4c5583b_0
+        - rdflib-jsonld=0.5.0=py37hf985489_2
+        - rdflib=5.0.0=py37hf985489_3
         - readline=8.0=h0678c8f_2
-        - scikit-image=0.17.2=py37h6d0141a_2
-        - scipy=1.5.2=py37h2702c91_0
+        - scikit-image=0.18.1=py37h010c265_0
+        - scipy=1.6.0=py37h6bb7d36_0
+        - setuptools=49.6.0=py37hf985489_3
         - snappy=1.1.8=hb1e8313_3
-        - sqlite=3.33.0=h960bd1c_0
-        - tk=8.6.10=hb0a8c7a_0
-        - tornado=6.0.4=py37h9bfed18_1
+        - sparqlwrapper=1.8.5=py37hf985489_1005
+        - spectate=1.0.0=py37hf985489_1
+        - sqlite=3.34.0=h17101e1_0
+        - terminado=0.9.2=py37hf985489_0
+        - tk=8.6.10=h0419947_1
+        - tornado=6.1=py37hf967b71_1
+        - widgetsnbextension=3.5.1=py37hf985489_4
         - xz=5.2.5=haf1e3a3_1
         - yaml=0.2.5=haf1e3a3_0
-        - zeromq=4.3.2=h4a8c4bd_3
-        - zfp=0.5.5=h4a8c4bd_1
-        - zlib=1.2.11=h7795811_1009
-        - zstd=1.4.5=h289c70a_2
+        - zeromq=4.3.3=h74dc148_3
+        - zfp=0.5.5=h046ec9c_4
+        - zlib=1.2.11=h7795811_1010
+        - zstd=1.4.8=hf387650_1
       win-64:
-        - argon2-cffi=20.1.0=py37h4ab8f01_1
+        - argon2-cffi=20.1.0=py37hcc03f2d_2
         - atomicwrites=1.4.0=pyh9f0ad1d_0
-        - blas=1.0=mkl
-        - bokeh=2.1.1=py37hc8dfbb8_0
-        - brotlipy=0.7.0=py37h4ab8f01_1000
-        - cffi=1.14.1=py37h26f1ce3_0
-        - colorama=0.4.3=py_0
-        - coverage=5.2.1=py37h4ab8f01_0
-        - cryptography=3.1=py37h26f1ce3_0
-        - cytoolz=0.10.1=py37hfa6e2cd_0
-        - freetype=2.10.2=hd328e21_0
-        - icc_rt=2019.0.0=h0cc432a_1
-        - imagecodecs-lite=2019.12.3=py37h44b1f71_1
-        - intel-openmp=2020.2=254
-        - ipykernel=5.3.4=py37h5ca1d4c_0
-        - jpeg=9b=vc14h4d7706e_1
-        - kiwisolver=1.2.0=py37heaa310e_0
-        - libblas=3.8.0=14_mkl
-        - libcblas=3.8.0=14_mkl
-        - liblapack=3.8.0=14_mkl
-        - libpng=1.6.37=ha81a0f5_2
-        - libsodium=1.0.17=h2fa13f4_0
-        - libtiff=4.0.9=hf1753bf_1
-        - llvmlite=0.34.0=py37h8b575af_1
+        - blosc=1.21.0=h0e60522_0
+        - bokeh=2.2.3=py37h03978a9_0
+        - brotli=1.0.9=h0e60522_4
+        - brotlipy=0.7.0=py37hcc03f2d_1001
+        - bzip2=1.0.8=h8ffe710_4
+        - ca-certificates=2020.12.5=h5b45459_0
+        - certifi=2020.12.5=py37h03978a9_1
+        - cffi=1.14.4=py37hd8e9650_1
+        - chardet=4.0.0=py37h03978a9_1
+        - charls=2.2.0=h39d44d4_0
+        - colorama=0.4.4=pyh9f0ad1d_0
+        - coverage=5.3.1=py37hcc03f2d_1
+        - cryptography=3.3.1=py37hd8e9650_1
+        - cytoolz=0.11.0=py37hcc03f2d_1
+        - dataclasses=0.7=pyhb2cacf7_7
+        - distributed=2021.1.0=py37h03978a9_1
+        - entrypoints=0.3=pyhd8ed1ab_1003
+        - freetype=2.10.4=h546665d_1
+        - giflib=5.2.1=h8d14728_2
+        - imagecodecs=2021.1.11=py37hfc4c502_1
+        - importlib-metadata=3.4.0=py37h03978a9_0
+        - importlib_resources=5.1.0=py37h03978a9_0
+        - intel-openmp=2020.3=h57928b3_311
+        - ipykernel=5.4.2=py37h7b7c402_0
+        - ipython=7.18.1=py37hc6149b9_1
+        - jedi=0.18.0=py37h03978a9_2
+        - jpeg=9d=h8ffe710_0
+        - jsonschema=3.2.0=py_2
+        - jupyter_core=4.7.0=py37h03978a9_0
+        - jxrlib=1.1=h8ffe710_2
+        - keepalive=0.5=py37h03978a9_5
+        - kiwisolver=1.3.1=py37h8c56517_1
+        - lcms2=2.11=h6a326e1_1
+        - lerc=2.2.1=h0e60522_0
+        - libaec=1.0.4=h39d44d4_1
+        - libblas=3.9.0=7_mkl
+        - libcblas=3.9.0=7_mkl
+        - libdeflate=1.7=h8ffe710_5
+        - libiconv=1.16=he774522_0
+        - liblapack=3.9.0=7_mkl
+        - libpng=1.6.37=h1d00b33_2
+        - libsodium=1.0.18=h8d14728_1
+        - libtiff=4.2.0=hc10be44_0
+        - libwebp-base=1.1.0=h8ffe710_3
+        - libxml2=2.9.10=hf5bbc77_3
+        - libxslt=1.1.33=h65864e5_2
+        - libzopfli=1.0.3=h0e60522_0
+        - llvmlite=0.35.0=py37habb0c8c_1
+        - lxml=4.6.2=py37hd07aab1_1
+        - lz4-c=1.9.3=h8ffe710_0
         - m2w64-gcc-libgfortran=5.3.0=6
         - m2w64-gcc-libs-core=5.3.0=7
         - m2w64-gcc-libs=5.3.0=7
         - m2w64-gmp=6.1.0=2
         - m2w64-libwinpthread-git=5.0.0.4634.697f757=2
-        - markupsafe=1.1.1=py37h8055547_1
-        - matplotlib-base=3.2.2=py37hab8957c_1
-        - mistune=0.8.4=py37h8055547_1001
-        - mkl-service=2.3.0=py37hfa6e2cd_0
-        - mkl=2019.4=245
-        - msgpack-python=1.0.0=py37heaa310e_1
+        - markupsafe=1.1.1=py37hcc03f2d_3
+        - matplotlib-base=3.3.3=py37h3379fd5_0
+        - mistune=0.8.4=py37hcc03f2d_1003
+        - mkl=2020.4=hb70f87d_311
+        - msgpack-python=1.0.2=py37h8c56517_1
         - msys2-conda-epoch=20160418=1
-        - nodejs=12.18.3=0
-        - numba=0.51.2=py37h414f9d2_0
-        - numpy=1.19.1=py37h7cee19a_2
-        - openssl=1.1.1g=he774522_1
-        - pandas=1.1.2=py37h1834ac0_0
-        - pandoc=2.10.1=he774522_0
-        - pillow=5.2.0=py37h08bbbbd_0
-        - psutil=5.7.2=py37h4ab8f01_0
-        - pyrsistent=0.16.0=py37h8055547_0
-        - python=3.7.8=h60c2a47_1_cpython
-        - pywavelets=1.1.1=py37h3a3b6f7_2
-        - pywin32=227=py37hfa6e2cd_0
-        - pywinpty=0.5.7=py37_0
-        - pyyaml=5.1.2=py37hfa6e2cd_0
-        - pyzmq=19.0.2=py37h453f00a_0
-        - scikit-image=0.17.2=py37h414f9d2_2
-        - scipy=1.5.2=py37h9439919_0
-        - sqlite=3.33.0=he774522_0
-        - tifffile=2020.6.3=py_0
-        - tk=8.6.7=vc14hb68737d_1
-        - tornado=6.0.4=py37hfa6e2cd_0
-        - vc=14.1=h869be7e_1
-        - vs2015_runtime=14.16.27012=h30e32a0_2
-        - win_inet_pton=1.1.0=py37_0
-        - wincertstore=0.2=py37_1003
+        - nbconvert=6.0.7=py37h03978a9_3
+        - nodejs=12.19.0=h57928b3_2
+        - notebook=6.2.0=py37h03978a9_0
+        - numba=0.52.0=py37h08fd248_0
+        - numpy=1.19.5=py37hd20adf4_1
+        - openjpeg=2.4.0=h48faf41_0
+        - openssl=1.1.1i=h8ffe710_0
+        - pandas=1.2.1=py37h08fd248_0
+        - pandoc=2.11.3.2=h8ffe710_0
+        - parso=0.8.1=pyhd8ed1ab_0
+        - pickleshare=0.7.5=py_1003
+        - pillow=8.1.0=py37hdec93a9_1
+        - pluggy=0.13.1=py37h03978a9_4
+        - psutil=5.8.0=py37hcc03f2d_1
+        - pyrsistent=0.17.3=py37hcc03f2d_2
+        - pysocks=1.7.1=py37h03978a9_3
+        - pytest=6.2.1=py37h03978a9_1
+        - python=3.7.9=h7840368_0_cpython
+        - pywavelets=1.1.1=py37hda49f71_3
+        - pywin32=300=py37hcc03f2d_0
+        - pywinpty=0.5.7=py37hc8dfbb8_1
+        - pyyaml=5.3.1=py37hcc03f2d_2
+        - pyzmq=21.0.1=py37h0d95fc2_0
+        - rdflib-jsonld=0.5.0=py37h03978a9_2
+        - rdflib=5.0.0=py37h03978a9_3
+        - scikit-image=0.18.1=py37h08fd248_0
+        - scipy=1.6.0=py37h6db1a17_0
+        - setuptools=49.6.0=py37h03978a9_3
+        - snappy=1.1.8=ha925a31_3
+        - sparqlwrapper=1.8.5=py37h03978a9_1005
+        - spectate=0.4.1=pyh9f0ad1d_0
+        - sqlite=3.34.0=h8ffe710_0
+        - terminado=0.9.2=py37h03978a9_0
+        - tk=8.6.10=h8ffe710_1
+        - tornado=6.1=py37hcc03f2d_1
+        - vc=14.2=hb210afc_2
+        - vs2015_runtime=14.28.29325=h5e1d092_0
+        - widgetsnbextension=3.5.1=py37h03978a9_4
+        - win_inet_pton=1.1.0=py37h03978a9_2
+        - wincertstore=0.2=py37h03978a9_1006
         - winpty=0.4.3=4
-        - yaml=0.1.7=vc14h4cb57cf_1
-        - zeromq=4.3.2=ha925a31_3
-        - zlib=1.2.11=vc14h1cdd9ab_1
+        - xz=5.2.5=h62dcd97_1
+        - yaml=0.2.5=he774522_0
+        - zeromq=4.3.3=h0e60522_3
+        - zfp=0.5.5=h0e60522_4
+        - zlib=1.2.11=h62dcd97_1010
+        - zstd=1.4.8=h4e2f164_1
   qa:
     locked: true
-    env_spec_hash: a6e34610fa847592d721b7ef6f3fcbd9fba6b0bc
+    env_spec_hash: 6dab99a282641dea3a8b82de43187f2ba4b3c147
     platforms:
       - linux-64
       - osx-64
@@ -371,19 +468,15 @@ env_specs:
         - black=20.8b1=py_1
         - bleach=3.2.1=pyh9f0ad1d_0
         - click=7.1.2=pyh9f0ad1d_0
-        - dataclasses=0.7=pyhb2cacf7_7
         - decorator=4.4.2=py_0
         - defusedxml=0.6.0=py_0
-        - entrypoints=0.3=pyhd8ed1ab_1003
         - flake8=3.8.4=py_0
         - idna=2.10=pyh9f0ad1d_0
         - importlib_metadata=3.4.0=hd8ed1ab_0
-        - ipython=7.18.1=py37hc6149b9_1
         - ipython_genutils=0.2.0=py_1
-        - isort=4.3.21=py37hc8dfbb8_1
+        - isort=5.7.0=pyhd8ed1ab_0
         - jinja2=2.11.2=pyh9f0ad1d_0
         - json5=0.9.5=pyh9f0ad1d_0
-        - jsonschema=3.2.0=py_2
         - jupyter_client=6.1.11=pyhd8ed1ab_1
         - jupyterlab=2.2.5=py_0
         - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
@@ -394,10 +487,7 @@ env_specs:
         - nest-asyncio=1.4.3=pyhd8ed1ab_0
         - packaging=20.8=pyhd3deb0d_0
         - pandocfilters=1.4.2=py_1
-        - parso=0.8.1=pyhd8ed1ab_0
         - pathspec=0.8.1=pyhd3deb0d_0
-        - pickleshare=0.7.5=py_1003
-        - pip=20.3.3=pyhd8ed1ab_0
         - prometheus_client=0.9.0=pyhd3deb0d_0
         - prompt-toolkit=3.0.10=pyha770c72_0
         - pycodestyle=2.6.0=pyh9f0ad1d_0
@@ -418,33 +508,35 @@ env_specs:
         - urllib3=1.26.2=pyhd8ed1ab_0
         - wcwidth=0.2.5=pyh9f0ad1d_2
         - webencodings=0.5.1=py_1
-        - wheel=0.36.2=pyhd3deb0d_0
         - zipp=3.4.0=py_0
       unix:
-        - pexpect=4.8.0=pyh9f0ad1d_2
         - ptyprocess=0.7.0=pyhd3deb0d_0
       linux-64:
         - _libgcc_mutex=0.1=conda_forge
         - _openmp_mutex=4.5=1_gnu
-        - argon2-cffi=20.1.0=py37h5e8e339_2
-        - brotlipy=0.7.0=py37h5e8e339_1001
+        - argon2-cffi=20.1.0=py37h8f50634_2
+        - brotlipy=0.7.0=py37hb5d75c8_1001
         - ca-certificates=2020.12.5=ha878542_0
         - certifi=2020.12.5=py37h89c1867_1
         - cffi=1.14.4=py37hc58025e_1
         - chardet=4.0.0=py37h89c1867_1
         - cryptography=3.3.1=py37h7f0c10b_1
+        - dataclasses=0.7=py37_0
+        - entrypoints=0.3=py37hc8dfbb8_1002
         - icu=68.1=h58526e2_0
         - importlib-metadata=3.4.0=py37h89c1867_0
         - ipykernel=5.4.2=py37h888b3d9_0
-        - jedi=0.18.0=py37h89c1867_2
+        - ipython=7.19.0=py37h888b3d9_2
+        - jedi=0.17.2=py37hc8dfbb8_1
+        - jsonschema=3.2.0=py37hc8dfbb8_1
         - jupyter_core=4.7.0=py37h89c1867_0
-        - ld_impl_linux-64=2.35.1=hea4e1c9_1
+        - ld_impl_linux-64=2.35.1=hed1e6ac_1
         - libffi=3.3=h58526e2_2
         - libgcc-ng=9.3.0=h2828fa1_18
         - libgomp=9.3.0=h2828fa1_18
-        - libsodium=1.0.18=h36c2ea0_1
+        - libsodium=1.0.18=h516909a_1
         - libstdcxx-ng=9.3.0=h6de172a_18
-        - libuv=1.40.0=h7f98852_0
+        - libuv=1.40.0=hd18ef5c_0
         - markupsafe=1.1.1=py37h5e8e339_3
         - mistune=0.8.4=py37h5e8e339_1003
         - mypy_extensions=0.4.3=py37h89c1867_3
@@ -454,6 +546,9 @@ env_specs:
         - notebook=6.2.0=py37h89c1867_0
         - openssl=1.1.1i=h7f98852_0
         - pandoc=2.11.3.2=h7f98852_0
+        - parso=0.7.1=pyh9f0ad1d_0
+        - pexpect=4.8.0=py37hc8dfbb8_1
+        - pickleshare=0.7.5=py37hc8dfbb8_1002
         - pyrsistent=0.17.3=py37h5e8e339_2
         - pysocks=1.7.1=py37h89c1867_3
         - python=3.7.9=hffdb5ce_0_cpython
@@ -463,7 +558,7 @@ env_specs:
         - setuptools=49.6.0=py37h89c1867_3
         - sqlite=3.34.0=h74cdb3f_0
         - terminado=0.9.2=py37h89c1867_0
-        - tk=8.6.10=h21135ba_1
+        - tk=8.6.10=hed695b0_1
         - tornado=6.1=py37h5e8e339_1
         - typed-ast=1.4.2=py37h5e8e339_0
         - xz=5.2.5=h516909a_1
@@ -478,10 +573,14 @@ env_specs:
         - cffi=1.14.4=py37hc5b2277_1
         - chardet=4.0.0=py37hf985489_1
         - cryptography=3.3.1=py37haf76d9e_1
+        - dataclasses=0.7=pyhb2cacf7_7
+        - entrypoints=0.3=pyhd8ed1ab_1003
         - icu=68.1=h74dc148_0
         - importlib-metadata=3.4.0=py37hf985489_0
         - ipykernel=5.4.2=py37he01cfaa_0
+        - ipython=7.18.1=py37hc6149b9_1
         - jedi=0.18.0=py37hf985489_2
+        - jsonschema=3.2.0=py_2
         - jupyter_core=4.7.0=py37hf985489_0
         - libcxx=11.0.0=h4c3b8ed_1
         - libffi=3.3=h046ec9c_2
@@ -496,6 +595,9 @@ env_specs:
         - notebook=6.2.0=py37hf985489_0
         - openssl=1.1.1i=h35c211d_0
         - pandoc=2.11.3.2=h35c211d_0
+        - parso=0.8.1=pyhd8ed1ab_0
+        - pexpect=4.8.0=pyh9f0ad1d_2
+        - pickleshare=0.7.5=py_1003
         - pyrsistent=0.17.3=py37hf967b71_2
         - pysocks=1.7.1=py37hf985489_3
         - python=3.7.9=h6c3b2c9_0_cpython
@@ -520,9 +622,13 @@ env_specs:
         - chardet=4.0.0=py37h03978a9_1
         - colorama=0.4.4=pyh9f0ad1d_0
         - cryptography=3.3.1=py37hd8e9650_1
+        - dataclasses=0.7=pyhb2cacf7_7
+        - entrypoints=0.3=pyhd8ed1ab_1003
         - importlib-metadata=3.4.0=py37h03978a9_0
         - ipykernel=5.4.2=py37h7b7c402_0
+        - ipython=7.18.1=py37hc6149b9_1
         - jedi=0.18.0=py37h03978a9_2
+        - jsonschema=3.2.0=py_2
         - jupyter_core=4.7.0=py37h03978a9_0
         - libsodium=1.0.18=h8d14728_1
         - m2w64-gcc-libgfortran=5.3.0=6
@@ -539,6 +645,8 @@ env_specs:
         - notebook=6.2.0=py37h03978a9_0
         - openssl=1.1.1i=h8ffe710_0
         - pandoc=2.11.3.2=h8ffe710_0
+        - parso=0.8.1=pyhd8ed1ab_0
+        - pickleshare=0.7.5=py_1003
         - pyrsistent=0.17.3=py37hcc03f2d_2
         - pysocks=1.7.1=py37h03978a9_3
         - python=3.7.9=h7840368_0_cpython
@@ -559,114 +667,132 @@ env_specs:
         - zeromq=4.3.3=h0e60522_3
   build:
     locked: true
-    env_spec_hash: 6edd7e4a8e68749d5b2750d762ae9c1ca97b4c67
+    env_spec_hash: bcd31b2b6ceae32cda53bdd935c86f9c8d4b5a4b
     platforms:
       - linux-64
       - osx-64
       - win-64
     packages:
       all:
-        - bleach=3.1.5=pyh9f0ad1d_0
-        - ca-certificates=2020.6.20=hecda079_0
-        - certifi=2020.6.20=py37hc8dfbb8_0
-        - chardet=3.0.4=py37hc8dfbb8_1006
-        - colorama=0.4.3=py_0
+        - bleach=3.2.1=pyh9f0ad1d_0
+        - colorama=0.4.4=pyh9f0ad1d_0
         - conda=4.8.3=py37hc8dfbb8_1
-        - docutils=0.16=py37hc8dfbb8_1
-        - entrypoints=0.3=py37hc8dfbb8_1001
-        - future=0.18.2=py37hc8dfbb8_1
         - idna=2.10=pyh9f0ad1d_0
-        - importlib-metadata=1.7.0=py37hc8dfbb8_0
-        - importlib_metadata=1.7.0=0
-        - keyring=21.4.0=py37hc8dfbb8_0
-        - packaging=20.4=pyh9f0ad1d_0
-        - pip=20.2.3=py_0
-        - pkginfo=1.5.0.1=py_0
+        - importlib_metadata=3.4.0=hd8ed1ab_0
+        - packaging=20.8=pyhd3deb0d_0
+        - pip=20.3.3=pyhd8ed1ab_0
+        - pkginfo=1.7.0=pyhd8ed1ab_0
         - pycparser=2.20=pyh9f0ad1d_2
-        - pygments=2.6.1=py_0
-        - pyopenssl=19.1.0=py_1
+        - pygments=2.7.4=pyhd8ed1ab_0
+        - pyopenssl=20.0.1=pyhd8ed1ab_0
         - pyparsing=2.4.7=pyh9f0ad1d_0
-        - pysocks=1.7.1=py37hc8dfbb8_1
         - python_abi=3.7=1_cp37m
-        - readme_renderer=24.0=pyh9f0ad1d_0
+        - readme_renderer=27.0=pyh9f0ad1d_0
         - requests-toolbelt=0.9.1=py_0
-        - requests=2.24.0=pyh9f0ad1d_0
+        - requests=2.25.1=pyhd3deb0d_0
         - rfc3986=1.4.0=pyh9f0ad1d_0
-        - setuptools=49.6.0=py37hc8dfbb8_0
         - six=1.15.0=pyh9f0ad1d_0
-        - tqdm=4.48.2=pyh9f0ad1d_0
-        - twine=3.2.0=py37hc8dfbb8_0
-        - urllib3=1.25.10=py_0
+        - tqdm=4.56.0=pyhd8ed1ab_0
+        - typing_extensions=3.7.4.3=py_0
+        - urllib3=1.26.2=pyhd8ed1ab_0
         - webencodings=0.5.1=py_1
-        - wheel=0.35.1=pyh9f0ad1d_0
-        - zipp=3.1.0=py_0
+        - wheel=0.36.2=pyhd3deb0d_0
+        - zipp=3.4.0=py_0
       linux-64:
         - _libgcc_mutex=0.1=conda_forge
         - _openmp_mutex=4.5=1_gnu
-        - brotlipy=0.7.0=py37h8f50634_1000
-        - cffi=1.14.1=py37h2b28604_0
-        - cmarkgfm=0.4.2=py37h516909a_2
-        - conda-package-handling=1.7.0=py37h8f50634_4
-        - cryptography=3.1=py37hb09aad4_0
-        - dbus=1.13.6=he372182_0
+        - brotlipy=0.7.0=py37hb5d75c8_1001
+        - ca-certificates=2020.12.5=ha878542_0
+        - certifi=2020.12.5=py37h89c1867_1
+        - cffi=1.14.4=py37hc58025e_1
+        - chardet=4.0.0=py37h89c1867_1
+        - cmarkgfm=0.4.2=py37h8f50634_3
+        - conda-package-handling=1.7.2=py37hb5d75c8_0
+        - cryptography=3.3.1=py37h7f0c10b_1
+        - dbus=1.13.6=hfdff14a_1
+        - docutils=0.16=py37h89c1867_3
         - expat=2.2.9=he1b5a44_2
-        - gettext=0.19.8.1=hc5be6a0_1002
-        - glib=2.65.0=h6f030ca_0
-        - jeepney=0.4.3=py_0
-        - ld_impl_linux-64=2.34=hc38a660_9
-        - libffi=3.2.1=he1b5a44_1007
-        - libgcc-ng=9.3.0=h24d8f2e_16
-        - libgomp=9.3.0=h24d8f2e_16
+        - gettext=0.19.8.1=h0b5b191_1005
+        - glib=2.66.4=hcd2ae1e_1
+        - importlib-metadata=3.4.0=py37h89c1867_0
+        - jeepney=0.6.0=pyhd8ed1ab_0
+        - keyring=21.8.0=py37h89c1867_0
+        - ld_impl_linux-64=2.35.1=hed1e6ac_1
+        - libffi=3.3=h58526e2_2
+        - libgcc-ng=9.3.0=h2828fa1_18
+        - libglib=2.66.4=h164308a_1
+        - libgomp=9.3.0=h2828fa1_18
         - libiconv=1.16=h516909a_0
-        - libstdcxx-ng=9.3.0=hdf63c60_16
-        - ncurses=6.2=he1b5a44_1
-        - openssl=1.1.1g=h516909a_1
+        - libstdcxx-ng=9.3.0=h6de172a_18
+        - ncurses=6.2=h58526e2_4
+        - openssl=1.1.1i=h7f98852_0
         - pcre=8.44=he1b5a44_0
-        - pycosat=0.6.3=py37h8f50634_1004
-        - python=3.7.8=h6f2ec95_1_cpython
+        - pycosat=0.6.3=py37h5e8e339_1006
+        - pysocks=1.7.1=py37h89c1867_3
+        - python=3.7.9=hffdb5ce_0_cpython
         - readline=8.0=he28a2e2_2
-        - ruamel_yaml=0.15.80=py37h8f50634_1002
-        - secretstorage=3.1.2=py37hc8dfbb8_1
-        - sqlite=3.33.0=h4cf870e_0
-        - tk=8.6.10=hed695b0_0
+        - ruamel_yaml=0.15.80=py37hb5d75c8_1003
+        - secretstorage=3.3.0=py37h89c1867_0
+        - setuptools=49.6.0=py37h89c1867_3
+        - sqlite=3.34.0=h74cdb3f_0
+        - tk=8.6.10=hed695b0_1
+        - twine=3.3.0=py37h89c1867_0
         - xz=5.2.5=h516909a_1
         - yaml=0.2.5=h516909a_0
-        - zlib=1.2.11=h516909a_1009
+        - zlib=1.2.11=h516909a_1010
       osx-64:
-        - brotlipy=0.7.0=py37h9bfed18_1000
-        - cffi=1.14.1=py37hf5b7abd_0
-        - cmarkgfm=0.4.2=py37h0b31af3_2
-        - conda-package-handling=1.7.0=py37h60d8a13_4
-        - cryptography=3.1=py37h94e4008_0
-        - libcxx=10.0.1=h5f48129_0
-        - libffi=3.2.1=hb1e8313_1007
-        - ncurses=6.2=hb1e8313_1
-        - openssl=1.1.1g=haf1e3a3_1
-        - pycosat=0.6.3=py37h9bfed18_1004
-        - python=3.7.8=hc9dea61_1_cpython
+        - brotlipy=0.7.0=py37hf967b71_1001
+        - ca-certificates=2020.12.5=h033912b_0
+        - certifi=2020.12.5=py37hf985489_1
+        - cffi=1.14.4=py37hc5b2277_1
+        - chardet=4.0.0=py37hf985489_1
+        - cmarkgfm=0.4.2=py37h50a09ed_3
+        - conda-package-handling=1.7.2=py37h395d20d_0
+        - cryptography=3.3.1=py37haf76d9e_1
+        - docutils=0.16=py37hf985489_3
+        - importlib-metadata=3.4.0=py37hf985489_0
+        - keyring=21.8.0=py37hf985489_0
+        - libcxx=11.0.0=h4c3b8ed_1
+        - libffi=3.3=h046ec9c_2
+        - ncurses=6.2=h2e338ed_4
+        - openssl=1.1.1i=h35c211d_0
+        - pycosat=0.6.3=py37hf967b71_1006
+        - pysocks=1.7.1=py37hf985489_3
+        - python=3.7.9=h6c3b2c9_0_cpython
         - readline=8.0=h0678c8f_2
-        - ruamel_yaml=0.15.80=py37h60d8a13_1002
-        - sqlite=3.33.0=h960bd1c_0
-        - tk=8.6.10=hb0a8c7a_0
+        - ruamel_yaml=0.15.80=py37hf967b71_1003
+        - setuptools=49.6.0=py37hf985489_3
+        - sqlite=3.34.0=h17101e1_0
+        - tk=8.6.10=h0419947_1
+        - twine=3.3.0=py37hf985489_0
         - xz=5.2.5=haf1e3a3_1
         - yaml=0.2.5=haf1e3a3_0
-        - zlib=1.2.11=h7795811_1009
+        - zlib=1.2.11=h7795811_1010
       win-64:
-        - brotlipy=0.7.0=py37h4ab8f01_1000
-        - cffi=1.14.1=py37h26f1ce3_0
-        - cmarkgfm=0.4.2=py37hfa6e2cd_2
-        - conda-package-handling=1.7.0=py37h4ab8f01_4
-        - cryptography=3.1=py37h26f1ce3_0
-        - menuinst=1.4.16=py37_0
-        - openssl=1.1.1g=he774522_1
-        - pycosat=0.6.3=py37h8055547_1004
-        - python=3.7.8=h60c2a47_1_cpython
-        - pywin32-ctypes=0.2.0=py37hc8dfbb8_1001
-        - pywin32=227=py37hfa6e2cd_0
-        - ruamel_yaml=0.15.71=py37hfa6e2cd_1000
-        - sqlite=3.33.0=he774522_0
-        - vc=14.1=h869be7e_1
-        - vs2015_runtime=14.16.27012=h30e32a0_2
-        - win_inet_pton=1.1.0=py37_0
-        - wincertstore=0.2=py37_1003
-        - yaml=0.1.7=vc14h4cb57cf_1
+        - brotlipy=0.7.0=py37hcc03f2d_1001
+        - ca-certificates=2020.12.5=h5b45459_0
+        - certifi=2020.12.5=py37h03978a9_1
+        - cffi=1.14.4=py37hd8e9650_1
+        - chardet=4.0.0=py37h03978a9_1
+        - cmarkgfm=0.4.2=py37hcc03f2d_3
+        - conda-package-handling=1.7.2=py37h6dbccfb_0
+        - cryptography=3.3.1=py37hd8e9650_1
+        - docutils=0.16=py37h03978a9_3
+        - importlib-metadata=3.4.0=py37h03978a9_0
+        - keyring=21.8.0=py37h03978a9_0
+        - menuinst=1.4.16=py37hc8dfbb8_1
+        - openssl=1.1.1i=h8ffe710_0
+        - pycosat=0.6.3=py37hcc03f2d_1006
+        - pysocks=1.7.1=py37h03978a9_3
+        - python=3.7.9=h7840368_0_cpython
+        - pywin32-ctypes=0.2.0=py37h03978a9_1003
+        - pywin32=300=py37hcc03f2d_0
+        - ruamel_yaml=0.15.80=py37hcc03f2d_1003
+        - setuptools=49.6.0=py37h03978a9_3
+        - sqlite=3.34.0=h8ffe710_0
+        - twine=3.3.0=py37h03978a9_0
+        - vc=14.2=hb210afc_2
+        - vs2015_runtime=14.28.29325=h5e1d092_0
+        - win_inet_pton=1.1.0=py37h03978a9_2
+        - wincertstore=0.2=py37h03978a9_1006
+        - yaml=0.2.5=he774522_0
diff --git a/anaconda-project.yml b/anaconda-project.yml
index 0863693..7f111f6 100644
--- a/anaconda-project.yml
+++ b/anaconda-project.yml
@@ -37,8 +37,7 @@ env_specs:
       - win-64
     channels:
       - https://conda.anaconda.org/conda-forge
-      - https://conda.anaconda.org/anaconda
-      - https://conda.anaconda.org/msys2
+      - nodefaults
     packages:
       - conda ==4.8.3
       - pip
@@ -53,12 +52,11 @@ env_specs:
       - win-64
     channels:
       - https://conda.anaconda.org/conda-forge
-      - https://conda.anaconda.org/anaconda
-      - https://conda.anaconda.org/msys2
+      - nodefaults
     packages:
       - black
       - flake8
-      - isort <5
+      - isort >=5
       - jupyterlab ==2.2.5
       - nbformat
       - nodejs >=12,<13.0.0a0
@@ -73,14 +71,14 @@ env_specs:
       - win-64
     channels:
       - https://conda.anaconda.org/conda-forge
-      - https://conda.anaconda.org/anaconda
-      - https://conda.anaconda.org/msys2
+      - nodefaults
     packages:
       - datashader
       - hvplot
       - importnb
-      - ipycytoscape >=1.0.3
+      - ipycytoscape >=1.0.3,<1.1.0
       - ipywidgets
+      - pyviz_comms <1.0.3
       - jupyterlab ==2.2.5
       - networkx >=2
       - nodejs >=12,<13.0.0a0
diff --git a/dodo.py b/dodo.py
index 8c32ddf..3ea325c 100644
--- a/dodo.py
+++ b/dodo.py
@@ -14,13 +14,20 @@
 import shutil
 import subprocess
 
-import _scripts.project as P
-import _scripts.utils as U
 from doit.action import CmdAction
-from doit.tools import PythonInteractiveAction, config_changed
+from doit.tools import LongRunning, PythonInteractiveAction, config_changed
 from yaml import safe_load
 
-os.environ["PYTHONIOENCODING"] = "utf-8"
+import _scripts.project as P
+import _scripts.utils as U
+
+os.environ.update(
+    CONDA_EXE="mamba",
+    CONDARC=str(P.CONDARC),
+    MAMBA_NO_BANNER="1",
+    PIP_DISABLE_PIP_VERSION_CHECK="1",
+    PYTHONIOENCODING="utf-8",
+)
 
 DOIT_CONFIG = {
     "backend": "sqlite3",
@@ -194,6 +201,8 @@ def _test():
                 *P.APR_DEV,
                 "jupyter",
                 "nbconvert",
+                "--to",
+                "html",
                 "--output-dir",
                 P.DIST_NBHTML,
                 "--execute",
@@ -247,7 +256,7 @@ def task_lint():
             name="black",
             file_dep=[*P.ALL_PY, P.OK_ENV["qa"]],
             actions=[
-                [*P.APR_QA, "isort", "-rc", *P.ALL_PY],
+                [*P.APR_QA, "isort", *P.ALL_PY],
                 [*P.APR_QA, "black", "--quiet", *P.ALL_PY],
             ],
         ),
@@ -277,15 +286,24 @@ def task_lint():
         ),
         P.OK_PRETTIER,
     )
-    yield _ok(
-        dict(
-            name="nblint",
-            file_dep=[P.YARN_INTEGRITY, *P.EXAMPLE_IPYNB, P.OK_ENV["qa"]],
-            actions=[[*P.APR_QA, *P.PYM, "_scripts.nblint", *P.EXAMPLE_IPYNB]],
-            targets=[P.NBLINT_HASHES],
-        ),
-        P.OK_NBLINT,
-    )
+
+    def _nblint(nb, nb_ok):
+        return _ok(
+            dict(
+                name=f"""nblint:{nb.stem}""",
+                file_dep=[P.YARN_INTEGRITY, P.OK_ENV["qa"], nb],
+                actions=[
+                    LongRunning([*P.APR_QA, *P.PYM, "_scripts.nblint", nb], shell=False)
+                ],
+            ),
+            nb_ok,
+        )
+
+    all_nb_lint_ok = {nb: P.OK_NBLINT / nb.stem for nb in P.EXAMPLE_IPYNB}
+
+    for nb, nb_ok in all_nb_lint_ok.items():
+        yield _nblint(nb, nb_ok)
+
     yield _ok(
         dict(
             name="all",
@@ -295,7 +313,7 @@ def task_lint():
                 P.OK_FLAKE8,
                 P.OK_PRETTIER,
                 P.OK_PYFLAKES,
-                P.OK_NBLINT,
+                *all_nb_lint_ok.values(),
             ],
         ),
         P.OK_LINT,
diff --git a/environment.yml b/environment.yml
index 6020087..dfef838 100644
--- a/environment.yml
+++ b/environment.yml
@@ -2,15 +2,15 @@ name: ipyradiant
 
 channels:
   - https://conda.anaconda.org/conda-forge
-  - https://conda.anaconda.org/anaconda
-  - https://conda.anaconda.org/msys2
+  - nodefaults
 
 dependencies:
   - datashader
   - hvplot
   - importnb
-  - ipycytoscape >=1.0.3
+  - ipycytoscape >=1.0.3,<1.1.0
   - ipywidgets
+  - pyviz_comms <1.0.3
   - jupyterlab ==2.2.5
   - networkx >=2
   - nodejs >=12,<13.0.0a0
diff --git a/examples/Cytoscape_Example.ipynb b/examples/Cytoscape_Example.ipynb
index b3b2e8e..850bae4 100644
--- a/examples/Cytoscape_Example.ipynb
+++ b/examples/Cytoscape_Example.ipynb
@@ -17,10 +17,10 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import traitlets as T\n",
-    "\n",
     "import ipywidgets as W\n",
     "import pandas as pd\n",
+    "import traitlets as T\n",
+    "\n",
     "from ipyradiant import CytoscapeVisualizer, FileManager, PathLoader\n",
     "from ipyradiant.loader.util import SUFFIX_FORMAT_MAP"
    ]
diff --git a/examples/Datashader_Example.ipynb b/examples/Datashader_Example.ipynb
index 083e155..d09a66e 100644
--- a/examples/Datashader_Example.ipynb
+++ b/examples/Datashader_Example.ipynb
@@ -16,11 +16,11 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "import ipywidgets as W\n",
     "import traitlets as T\n",
+    "from rdflib import Graph\n",
     "\n",
-    "import ipywidgets as W\n",
-    "from ipyradiant import DatashaderVisualizer, LayoutSelector\n",
-    "from rdflib import Graph"
+    "from ipyradiant import DatashaderVisualizer, LayoutSelector"
    ]
   },
   {
diff --git a/examples/ExampleWidgetCollapsing.ipynb b/examples/ExampleWidgetCollapsing.ipynb
index 690034a..32c6b7d 100644
--- a/examples/ExampleWidgetCollapsing.ipynb
+++ b/examples/ExampleWidgetCollapsing.ipynb
@@ -6,9 +6,8 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import traitlets as T\n",
-    "\n",
-    "import ipywidgets as W"
+    "import ipywidgets as W\n",
+    "import traitlets as T"
    ]
   },
   {
diff --git a/examples/FederatedQuery_Example.ipynb b/examples/FederatedQuery_Example.ipynb
index 38e44a2..a7addfe 100644
--- a/examples/FederatedQuery_Example.ipynb
+++ b/examples/FederatedQuery_Example.ipynb
@@ -20,8 +20,9 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import ipyradiant\n",
-    "from rdflib import Graph, Literal, URIRef, namespace"
+    "from rdflib import Graph, Literal, URIRef, namespace\n",
+    "\n",
+    "import ipyradiant"
    ]
   },
   {
diff --git a/examples/FileManager.ipynb b/examples/FileManager.ipynb
index 50de4b8..53f1952 100644
--- a/examples/FileManager.ipynb
+++ b/examples/FileManager.ipynb
@@ -15,10 +15,10 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import traitlets as T\n",
-    "\n",
     "import ipywidgets as W\n",
     "import pandas as pd\n",
+    "import traitlets as T\n",
+    "\n",
     "from ipyradiant import FileManager, PathLoader, UpLoader\n",
     "from ipyradiant.loader.util import SUFFIX_FORMAT_MAP"
    ]
diff --git a/examples/Improved_Vis.ipynb b/examples/Improved_Vis.ipynb
index 5869328..310d095 100644
--- a/examples/Improved_Vis.ipynb
+++ b/examples/Improved_Vis.ipynb
@@ -11,9 +11,10 @@
     "import ipycytoscape\n",
     "import networkx as nx\n",
     "import rdflib\n",
+    "from rdflib.namespace import RDFS\n",
+    "\n",
     "from ipyradiant import FileManager, InteractiveViewer, PathLoader\n",
-    "from ipyradiant.rdf2nx import RDF2NX\n",
-    "from rdflib.namespace import RDFS"
+    "from ipyradiant.rdf2nx import RDF2NX"
    ]
   },
   {
diff --git a/examples/JSONWidget_Example.ipynb b/examples/JSONWidget_Example.ipynb
index 5ac79d5..5f18874 100644
--- a/examples/JSONWidget_Example.ipynb
+++ b/examples/JSONWidget_Example.ipynb
@@ -8,15 +8,15 @@
    "source": [
     "import json\n",
     "\n",
-    "from IPython.display import JSON, display\n",
-    "\n",
     "import ipycytoscape\n",
     "import ipywidgets as W\n",
     "import networkx as nx\n",
     "import rdflib\n",
+    "from IPython.display import JSON, display\n",
+    "from rdflib.namespace import RDFS\n",
+    "\n",
     "from ipyradiant import FileManager, PathLoader\n",
-    "from ipyradiant.rdf2nx import RDF2NX\n",
-    "from rdflib.namespace import RDFS"
+    "from ipyradiant.rdf2nx import RDF2NX"
    ]
   },
   {
diff --git a/examples/JSON_Interactive_Example.ipynb b/examples/JSON_Interactive_Example.ipynb
index c4b59bc..9ee63b0 100644
--- a/examples/JSON_Interactive_Example.ipynb
+++ b/examples/JSON_Interactive_Example.ipynb
@@ -15,15 +15,15 @@
    "source": [
     "import json\n",
     "\n",
-    "from IPython.display import JSON, display\n",
-    "\n",
     "import ipycytoscape\n",
     "import ipywidgets as W\n",
     "import networkx as nx\n",
     "import rdflib\n",
+    "from IPython.display import JSON, display\n",
+    "from rdflib.namespace import RDFS\n",
+    "\n",
     "from ipyradiant import FileManager, InteractiveViewer, PathLoader\n",
-    "from ipyradiant.rdf2nx import RDF2NX, URItoID, URItoShortID\n",
-    "from rdflib.namespace import RDFS"
+    "from ipyradiant.rdf2nx import RDF2NX, URItoID, URItoShortID"
    ]
   },
   {
diff --git a/examples/MultiPanelSelectWidget.ipynb b/examples/MultiPanelSelectWidget.ipynb
index c8d3d11..5c90874 100644
--- a/examples/MultiPanelSelectWidget.ipynb
+++ b/examples/MultiPanelSelectWidget.ipynb
@@ -20,6 +20,7 @@
    "outputs": [],
    "source": [
     "import ipywidgets as W\n",
+    "\n",
     "from ipyradiant import MultiPanelSelect"
    ]
   },
diff --git a/examples/RDF_to_NX.ipynb b/examples/RDF_to_NX.ipynb
index f78c9b4..b194b76 100644
--- a/examples/RDF_to_NX.ipynb
+++ b/examples/RDF_to_NX.ipynb
@@ -114,9 +114,10 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "from ipyradiant.rdf2nx import URItoID, URItoShortID\n",
     "from rdflib.namespace import RDFS\n",
     "\n",
+    "from ipyradiant.rdf2nx import URItoID, URItoShortID\n",
+    "\n",
     "uri = RDFS.label\n",
     "ns = {\"rdfs\": str(RDFS)}\n",
     "print(f\"URItoID:\\n  -  {uri} -> {URItoID(uri)}\")\n",
diff --git a/examples/RemoteQuery_Example.ipynb b/examples/RemoteQuery_Example.ipynb
index b84fbbe..cb7ed10 100644
--- a/examples/RemoteQuery_Example.ipynb
+++ b/examples/RemoteQuery_Example.ipynb
@@ -30,19 +30,19 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import traitlets as T\n",
-    "\n",
     "import ipywidgets as W\n",
     "import pandas as pd\n",
+    "import traitlets as T\n",
+    "from rdflib import BNode, Graph, Literal, URIRef, namespace\n",
+    "from SPARQLWrapper import JSON, XML, SPARQLWrapper\n",
+    "\n",
     "from ipyradiant import (\n",
     "    CytoscapeVisualizer,\n",
     "    FileManager,\n",
     "    PathLoader,\n",
     "    QueryWidget,\n",
     "    service_patch_rdflib,\n",
-    ")\n",
-    "from rdflib import BNode, Graph, Literal, URIRef, namespace\n",
-    "from SPARQLWrapper import JSON, XML, SPARQLWrapper"
+    ")"
    ]
   },
   {
diff --git a/examples/Tab_App_Example.ipynb b/examples/Tab_App_Example.ipynb
index 0d26aa7..ff9aea7 100644
--- a/examples/Tab_App_Example.ipynb
+++ b/examples/Tab_App_Example.ipynb
@@ -16,11 +16,11 @@
    "metadata": {},
    "outputs": [],
    "source": [
+    "import ipywidgets as W\n",
     "import traitlets as T\n",
+    "from rdflib import BNode, Graph\n",
     "\n",
-    "import ipywidgets as W\n",
-    "from ipyradiant import CytoscapeVisualizer, FileManager, PathLoader, QueryWidget\n",
-    "from rdflib import BNode, Graph"
+    "from ipyradiant import CytoscapeVisualizer, FileManager, PathLoader, QueryWidget"
    ]
   },
   {
diff --git a/examples/Test_Cytoscape.ipynb b/examples/Test_Cytoscape.ipynb
index f20e992..83ad806 100644
--- a/examples/Test_Cytoscape.ipynb
+++ b/examples/Test_Cytoscape.ipynb
@@ -24,9 +24,9 @@
     "\n",
     "with importnb.Notebook():\n",
     "    try:\n",
-    "        from .Cytoscape_Example import cy, pl, W, cy_ex, fm\n",
+    "        from .Cytoscape_Example import W, cy, cy_ex, fm, pl\n",
     "    except ImportError:\n",
-    "        from Cytoscape_Example import cy, pl, W, cy_ex, fm"
+    "        from Cytoscape_Example import W, cy, cy_ex, fm, pl"
    ]
   },
   {
diff --git a/examples/Test_Datashader.ipynb b/examples/Test_Datashader.ipynb
index 9ca1ce2..690058f 100644
--- a/examples/Test_Datashader.ipynb
+++ b/examples/Test_Datashader.ipynb
@@ -22,14 +22,15 @@
     "from pathlib import Path\n",
     "\n",
     "import importnb\n",
-    "from ipyradiant import FileManager, PathLoader\n",
     "from rdflib import Graph\n",
     "\n",
+    "from ipyradiant import FileManager, PathLoader\n",
+    "\n",
     "with importnb.Notebook():\n",
     "    try:\n",
-    "        from .Datashader_Example import ds_ex, ds, ls, sn, W, T\n",
+    "        from .Datashader_Example import T, W, ds, ds_ex, ls, sn\n",
     "    except ImportError:\n",
-    "        from Datashader_Example import ds_ex, ds, ls, sn, W, T"
+    "        from Datashader_Example import T, W, ds, ds_ex, ls, sn"
    ]
   },
   {
diff --git a/examples/Test_GraphExploreNodeSelection.ipynb b/examples/Test_GraphExploreNodeSelection.ipynb
index a3420b8..2823c28 100644
--- a/examples/Test_GraphExploreNodeSelection.ipynb
+++ b/examples/Test_GraphExploreNodeSelection.ipynb
@@ -31,23 +31,23 @@
     "with importnb.Notebook():\n",
     "    try:\n",
     "        from GraphExploreNodeSelection import (\n",
-    "            ge_selector,\n",
-    "            lw,\n",
     "            LEN_SSSW_VALUES,\n",
     "            LEN_TSSW_VALUES,\n",
     "            SSSW_VALUES,\n",
     "            TSSW_VALUES,\n",
     "            W,\n",
+    "            ge_selector,\n",
+    "            lw,\n",
     "        )\n",
     "    except GraphExploreNodeSelection:\n",
     "        from .GraphExplorer import (\n",
-    "            ge_selector,\n",
-    "            lw,\n",
     "            LEN_SSSW_VALUES,\n",
     "            LEN_TSSW_VALUES,\n",
     "            SSSW_VALUES,\n",
     "            TSSW_VALUES,\n",
     "            W,\n",
+    "            ge_selector,\n",
+    "            lw,\n",
     "        )"
    ]
   },
diff --git a/examples/Test_GraphExplorer.ipynb b/examples/Test_GraphExplorer.ipynb
index 90f2b59..7710b12 100644
--- a/examples/Test_GraphExplorer.ipynb
+++ b/examples/Test_GraphExplorer.ipynb
@@ -30,21 +30,9 @@
     "\n",
     "with importnb.Notebook():\n",
     "    try:\n",
-    "        from GraphExplorer import (\n",
-    "            ge,\n",
-    "            lw,\n",
-    "            SSSW_VALUES,\n",
-    "            TSSW_VALUES,\n",
-    "            NODE_TO_SELECT,\n",
-    "        )\n",
+    "        from GraphExplorer import NODE_TO_SELECT, SSSW_VALUES, TSSW_VALUES, ge, lw\n",
     "    except GraphExplorer:\n",
-    "        from .GraphExplorer import (\n",
-    "            ge,\n",
-    "            lw,\n",
-    "            SSSW_VALUES,\n",
-    "            TSSW_VALUES,\n",
-    "            NODE_TO_SELECT,\n",
-    "        )"
+    "        from .GraphExplorer import NODE_TO_SELECT, SSSW_VALUES, TSSW_VALUES, ge, lw"
    ]
   },
   {
diff --git a/examples/Test_InteractiveViewer.ipynb b/examples/Test_InteractiveViewer.ipynb
index dda1e69..9311d71 100644
--- a/examples/Test_InteractiveViewer.ipynb
+++ b/examples/Test_InteractiveViewer.ipynb
@@ -15,6 +15,7 @@
    "source": [
     "import importnb\n",
     "import rdflib\n",
+    "\n",
     "from ipyradiant import FileManager, GetOutgoingPredicateObjects, PathLoader\n",
     "\n",
     "with importnb.Notebook():\n",
diff --git a/examples/Test_MultiPanelSelect_Widget.ipynb b/examples/Test_MultiPanelSelect_Widget.ipynb
index 9fafe61..37ed4c7 100644
--- a/examples/Test_MultiPanelSelect_Widget.ipynb
+++ b/examples/Test_MultiPanelSelect_Widget.ipynb
@@ -23,9 +23,9 @@
     "\n",
     "with importnb.Notebook():\n",
     "    try:\n",
-    "        from MultiPanelSelectWidget import sw, W\n",
+    "        from MultiPanelSelectWidget import W, sw\n",
     "    except ImportError:\n",
-    "        from .MultiPanelSelectWidget import sw, W"
+    "        from .MultiPanelSelectWidget import W, sw"
    ]
   },
   {
diff --git a/examples/Test_Tab_App.ipynb b/examples/Test_Tab_App.ipynb
index 30a5170..f8ac65d 100644
--- a/examples/Test_Tab_App.ipynb
+++ b/examples/Test_Tab_App.ipynb
@@ -27,9 +27,9 @@
     "\n",
     "with importnb.Notebook():\n",
     "    try:\n",
-    "        from Tab_App_Example import tabs, W\n",
+    "        from Tab_App_Example import W, tabs\n",
     "    except ImportError:\n",
-    "        from .Tab_App_Example import tabs, W"
+    "        from .Tab_App_Example import W, tabs"
    ]
   },
   {
diff --git a/postBuild b/postBuild
index a164dba..12582eb 100644
--- a/postBuild
+++ b/postBuild
@@ -1,4 +1,5 @@
 #!/usr/bin/env bash
+# this runs after `environment.yml` has been installed with `mamba`
 set -eux
 
 # prepare
diff --git a/setup.cfg b/setup.cfg
index e9830ba..f06267b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -50,3 +50,8 @@ where =
 [flake8]
 max-line-length = 88
 ignore = E203, E501, W503
+
+[isort]
+profile = black
+multi_line_output = 3
+
diff --git a/src/ipyradiant/basic_tools/object_literal_collapsing.py b/src/ipyradiant/basic_tools/object_literal_collapsing.py
index 483cfac..29bf395 100644
--- a/src/ipyradiant/basic_tools/object_literal_collapsing.py
+++ b/src/ipyradiant/basic_tools/object_literal_collapsing.py
@@ -3,10 +3,9 @@
 import logging
 from typing import List, Union
 
-import traitlets as T
-
 import ipywidgets as W
 import networkx
+import traitlets as T
 from rdflib import Graph, URIRef
 from rdflib.extras.external_graph_libs import rdflib_to_networkx_digraph
 from rdflib.namespace import NamespaceManager
diff --git a/src/ipyradiant/basic_tools/selection_widget.py b/src/ipyradiant/basic_tools/selection_widget.py
index aa4c854..754168e 100644
--- a/src/ipyradiant/basic_tools/selection_widget.py
+++ b/src/ipyradiant/basic_tools/selection_widget.py
@@ -1,8 +1,7 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
-import traitlets as trt
-
 import ipywidgets as ipyw
+import traitlets as trt
 
 
 class MultiPanelSelect(ipyw.HBox):
diff --git a/src/ipyradiant/basic_tools/uri_widgets.py b/src/ipyradiant/basic_tools/uri_widgets.py
index 9bb53e9..b61fe1e 100644
--- a/src/ipyradiant/basic_tools/uri_widgets.py
+++ b/src/ipyradiant/basic_tools/uri_widgets.py
@@ -1,8 +1,7 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 from rdflib import URIRef
 
 
diff --git a/src/ipyradiant/loader/base.py b/src/ipyradiant/loader/base.py
index a9e76e6..240e9ab 100644
--- a/src/ipyradiant/loader/base.py
+++ b/src/ipyradiant/loader/base.py
@@ -2,9 +2,8 @@
 # Distributed under the terms of the Modified BSD License.
 
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 from rdflib import BNode, Graph
 
 from .util import guess_format
diff --git a/src/ipyradiant/loader/manager.py b/src/ipyradiant/loader/manager.py
index c5e9234..70041c4 100644
--- a/src/ipyradiant/loader/manager.py
+++ b/src/ipyradiant/loader/manager.py
@@ -3,9 +3,8 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 from rdflib import BNode, Graph
 
 from .base import BaseLoader
diff --git a/src/ipyradiant/loader/path.py b/src/ipyradiant/loader/path.py
index 153c37b..219545a 100644
--- a/src/ipyradiant/loader/path.py
+++ b/src/ipyradiant/loader/path.py
@@ -4,9 +4,8 @@
 # Distributed under the terms of the Modified BSD License.
 from pathlib import Path
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 
 from .base import BaseLoader
 from .util import SUFFIX_FORMAT_MAP
diff --git a/src/ipyradiant/loader/upload.py b/src/ipyradiant/loader/upload.py
index f922361..c3b02a9 100644
--- a/src/ipyradiant/loader/upload.py
+++ b/src/ipyradiant/loader/upload.py
@@ -3,9 +3,8 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 
 from .base import BaseLoader
 from .util import SUFFIX_FORMAT_MAP
diff --git a/src/ipyradiant/query/namespace_manager.py b/src/ipyradiant/query/namespace_manager.py
index eb70d01..2d73570 100644
--- a/src/ipyradiant/query/namespace_manager.py
+++ b/src/ipyradiant/query/namespace_manager.py
@@ -5,9 +5,8 @@
 
 import re
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 from rdflib.namespace import RDF, RDFS, XSD
 
 default_ns = {
diff --git a/src/ipyradiant/query/query_constructor.py b/src/ipyradiant/query/query_constructor.py
index 40d704c..949bd89 100644
--- a/src/ipyradiant/query/query_constructor.py
+++ b/src/ipyradiant/query/query_constructor.py
@@ -3,14 +3,13 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
+import ipywidgets as W
 import traitlets as T
 from pygments import highlight
 from pygments.formatters import HtmlFormatter
 from pygments.lexers.rdf import SparqlLexer
 from pygments.styles import STYLE_MAP
 
-import ipywidgets as W
-
 from .query_form import QueryInput
 
 # TODO improve
diff --git a/src/ipyradiant/query/query_form.py b/src/ipyradiant/query/query_form.py
index c3611ef..7560f99 100644
--- a/src/ipyradiant/query/query_form.py
+++ b/src/ipyradiant/query/query_form.py
@@ -3,9 +3,8 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 
 from .namespace_manager import NamespaceManager
 
diff --git a/src/ipyradiant/query/query_widget.py b/src/ipyradiant/query/query_widget.py
index 62c3bc5..acd93e6 100644
--- a/src/ipyradiant/query/query_widget.py
+++ b/src/ipyradiant/query/query_widget.py
@@ -5,10 +5,9 @@
 
 import re
 
-import traitlets as T
-
 import ipywidgets as W
 import qgrid
+import traitlets as T
 from pandas import DataFrame
 from rdflib import Graph, URIRef
 
diff --git a/src/ipyradiant/visualization/base.py b/src/ipyradiant/visualization/base.py
index 18af771..dbb3fcf 100644
--- a/src/ipyradiant/visualization/base.py
+++ b/src/ipyradiant/visualization/base.py
@@ -3,11 +3,10 @@
 
 import types
 
-import traitlets as T
-
 import ipywidgets as W
 import networkx as nx
 import networkx.drawing.layout as nx_layout
+import traitlets as T
 from rdflib import Graph, URIRef
 
 
diff --git a/src/ipyradiant/visualization/cytoscape.py b/src/ipyradiant/visualization/cytoscape.py
index 2b279b7..7bbb1c3 100644
--- a/src/ipyradiant/visualization/cytoscape.py
+++ b/src/ipyradiant/visualization/cytoscape.py
@@ -3,9 +3,8 @@
 
 from pathlib import Path
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 from ipycytoscape import CytoscapeWidget
 from rdflib import Graph, Literal, URIRef
 from rdflib.namespace import RDF
diff --git a/src/ipyradiant/visualization/datashader_vis.py b/src/ipyradiant/visualization/datashader_vis.py
index 8a89d9b..85f6198 100644
--- a/src/ipyradiant/visualization/datashader_vis.py
+++ b/src/ipyradiant/visualization/datashader_vis.py
@@ -1,12 +1,11 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import IPython
-import traitlets as T
-
 import holoviews as hv
+import IPython
 import ipywidgets as W
 import networkx as nx
+import traitlets as T
 from bokeh.models import HoverTool
 from holoviews import streams
 from holoviews.operation.datashader import bundle_graph
diff --git a/src/ipyradiant/visualization/explore/graph_explorer.py b/src/ipyradiant/visualization/explore/graph_explorer.py
index 3666b91..df25769 100644
--- a/src/ipyradiant/visualization/explore/graph_explorer.py
+++ b/src/ipyradiant/visualization/explore/graph_explorer.py
@@ -1,11 +1,10 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as T
-from IPython.display import JSON, display
-
 import ipywidgets as W
+import traitlets as T
 from ipycytoscape import CytoscapeWidget
+from IPython.display import JSON, display
 from networkx import Graph as NXGraph
 from rdflib import Graph as RDFGraph
 
diff --git a/src/ipyradiant/visualization/interactive_exploration.py b/src/ipyradiant/visualization/interactive_exploration.py
index d9b18f0..b2171e4 100644
--- a/src/ipyradiant/visualization/interactive_exploration.py
+++ b/src/ipyradiant/visualization/interactive_exploration.py
@@ -1,12 +1,12 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as trt
-
 import ipycytoscape
 import ipywidgets as W
 import rdflib
+import traitlets as trt
 from ipycytoscape import Edge, Node
+
 from ipyradiant.query.api import SPARQLQueryFramer
 from ipyradiant.rdf2nx.uri_converter import URItoID
 
diff --git a/src/ipyradiant/visualization/tools.py b/src/ipyradiant/visualization/tools.py
index 8f5027c..191d591 100644
--- a/src/ipyradiant/visualization/tools.py
+++ b/src/ipyradiant/visualization/tools.py
@@ -1,9 +1,8 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import traitlets as T
-
 import ipywidgets as W
+import traitlets as T
 
 from .base import VisualizerBase
 


Test patch:
diff --git a/src/ipyradiant/tests/test_CustomURI.py b/src/ipyradiant/tests/test_CustomURI.py
index 420a348..992e13a 100644
--- a/src/ipyradiant/tests/test_CustomURI.py
+++ b/src/ipyradiant/tests/test_CustomURI.py
@@ -2,9 +2,10 @@
 # Distributed under the terms of the Modified BSD License.
 import unittest
 
-from ipyradiant import CustomURIRef
 from rdflib import Graph, URIRef
 
+from ipyradiant import CustomURIRef
+
 
 class Testing(unittest.TestCase):
     namespaces = {"ex": "www.example.org/"}
diff --git a/src/ipyradiant/tests/test_PredCollapsing.py b/src/ipyradiant/tests/test_PredCollapsing.py
index 9a78d3e..3107634 100644
--- a/src/ipyradiant/tests/test_PredCollapsing.py
+++ b/src/ipyradiant/tests/test_PredCollapsing.py
@@ -2,9 +2,10 @@
 # Distributed under the terms of the Modified BSD License.
 import pytest
 import rdflib
-from ipyradiant import CustomURIRef, collapse_predicates
 from rdflib import Graph
 
+from ipyradiant import CustomURIRef, collapse_predicates
+
 
 @pytest.fixture(scope="module")
 def test_graph():
diff --git a/src/ipyradiant/tests/test_rdf2nx.py b/src/ipyradiant/tests/test_rdf2nx.py
index fff6428..f52dbbe 100644
--- a/src/ipyradiant/tests/test_rdf2nx.py
+++ b/src/ipyradiant/tests/test_rdf2nx.py
@@ -1,9 +1,10 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
-from ipyradiant.rdf2nx import RDF2NX
 from rdflib import URIRef
 from rdflib.namespace import RDF
 
+from ipyradiant.rdf2nx import RDF2NX
+
 
 def test_rdf2nx(example_ns, SCHEMA, simple_rdf_graph):
     """A simple test for the rdf2nx converter.
diff --git a/src/ipyradiant/tests/test_servicepatch_rdflib.py b/src/ipyradiant/tests/test_servicepatch_rdflib.py
index 4d72a1c..5f53fa6 100644
--- a/src/ipyradiant/tests/test_servicepatch_rdflib.py
+++ b/src/ipyradiant/tests/test_servicepatch_rdflib.py
@@ -3,9 +3,10 @@
 # Copyright (c) 2021 ipyradiant contributors.
 # Distributed under the terms of the Modified BSD License.
 
-import ipyradiant
 import rdflib
 
+import ipyradiant
+
 LINKEDDATA_QUERY = """
     SELECT DISTINCT ?s ?p ?o
         WHERE {