diff --git a/README.md b/README.md
index 0393ed9..f1e8696 100644
--- a/README.md
+++ b/README.md
@@ -40,9 +40,9 @@ them.
The release of JupyterLab 3 has made some version compatibility unpredictable. Below are
some researched combinations that should work.
-| `jupyterlab` | `ipycytoscape` | `pyviz_comms` | `pip install` |
-| ------------ | ---------------- | ------------- | ------------------ |
-| `>=3,<4` | `>=1.1.0` | `>=1.0.3` | `ipyradiant[lab3]` |
+| `jupyterlab` | `ipycytoscape` | `pyviz_comms` | `pip install` |
+| ------------ | -------------- | ------------- | ------------------ |
+| `>=3,<4` | `>=1.1.0` | `>=1.0.3` | `ipyradiant[lab3]` |
## Install
diff --git a/anaconda-project-lock.yml b/anaconda-project-lock.yml
index 514ff4d..444358b 100644
--- a/anaconda-project-lock.yml
+++ b/anaconda-project-lock.yml
@@ -21,778 +21,782 @@ env_specs:
locked: true
env_spec_hash: 3a5692c6b256101c97521f67262da72ea264656c
platforms:
- - linux-64
- - osx-64
- - win-64
+ - linux-64
+ - osx-64
+ - win-64
packages:
all:
- - appdirs=1.4.4=pyh9f0ad1d_0
- - async_generator=1.10=py_0
- - attrs=20.3.0=pyhd3deb0d_0
- - babel=2.9.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.3.0=pyh44b312d_0
- - cachetools=4.2.1=pyhd8ed1ab_0
- - click=7.1.2=pyh9f0ad1d_0
- - cloudpickle=1.6.0=py_0
- - colorcet=2.0.6=pyhd8ed1ab_0
- - cycler=0.10.0=py_2
- - dask-core=2021.2.0=pyhd8ed1ab_0
- - dask=2021.2.0=pyhd8ed1ab_0
- - dataclasses=0.7=pyhb2cacf7_7
- - datashader=0.12.0=pyhd3deb0d_0
- - datashape=0.5.4=py_1
- - decorator=4.4.2=py_0
- - defusedxml=0.6.0=py_0
- - entrypoints=0.3=pyhd8ed1ab_1003
- - frozendict=1.2=pyh9f0ad1d_3
- - fsspec=0.8.5=pyhd8ed1ab_0
- - heapdict=1.0.1=py_0
- - holoviews=1.14.1=pyhd3deb0d_0
- - html5lib=1.1=pyh9f0ad1d_0
- - hvplot=0.7.0=pyhd3deb0d_0
- - idna=2.10=pyh9f0ad1d_0
- - imageio=2.9.0=py_0
- - importlib_metadata=3.4.0=hd8ed1ab_0
- - importnb=0.7.0=pyhd8ed1ab_0
- - iniconfig=1.1.1=pyh9f0ad1d_0
- - ipycytoscape=1.2.0=pyhd8ed1ab_0
- - ipython_genutils=0.2.0=py_1
- - ipywidgets=7.6.3=pyhd3deb0d_0
- - isodate=0.6.0=py_1
- - jinja2=2.11.3=pyh44b312d_0
- - json5=0.9.5=pyh9f0ad1d_0
- - jsonschema=3.2.0=py_2
- - jupyter_client=6.1.11=pyhd8ed1ab_1
- - jupyterlab=3.0.7=pyhd8ed1ab_0
- - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
- - jupyterlab_server=2.2.0=pyhd8ed1ab_0
- - jupyterlab_widgets=1.0.0=pyhd8ed1ab_1
- - locket=0.2.0=py_2
- - markdown=3.3.3=pyh9f0ad1d_0
- - more-itertools=8.7.0=pyhd8ed1ab_0
- - multipledispatch=0.6.0=py_0
- - nbclassic=0.2.6=pyhd8ed1ab_0
- - nbclient=0.5.2=pyhd8ed1ab_0
- - nbformat=5.1.2=pyhd8ed1ab_1
- - nest-asyncio=1.4.3=pyhd8ed1ab_0
- - networkx=2.5=py_0
- - olefile=0.46=pyh9f0ad1d_1
- - owlrl=5.2.1=py_0
- - packaging=20.9=pyh44b312d_0
- - pandocfilters=1.4.2=py_1
- - panel=0.10.3=pyhd8ed1ab_0
- - param=1.10.1=pyhd3deb0d_0
- - parso=0.8.1=pyhd8ed1ab_0
- - partd=1.1.0=py_0
- - pickleshare=0.7.5=py_1003
- - pip=21.0.1=pyhd8ed1ab_0
- - pooch=1.3.0=pyhd8ed1ab_0
- - prometheus_client=0.9.0=pyhd3deb0d_0
- - prompt-toolkit=3.0.16=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.7.4=pyhd8ed1ab_0
- - pyld=2.0.3=pyh9f0ad1d_0
- - pyopenssl=20.0.1=pyhd8ed1ab_0
- - pyparsing=2.4.7=pyh9f0ad1d_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=2021.1=pyhd8ed1ab_0
- - pyviz_comms=2.0.1=pyhd3deb0d_0
- - requests=2.25.1=pyhd3deb0d_0
- - requests_cache=0.4.13=py_0
- - send2trash=1.5.0=py_0
- - six=1.15.0=pyh9f0ad1d_0
- - sortedcontainers=2.3.0=pyhd8ed1ab_0
- - tblib=1.6.0=py_0
- - testpath=0.4.4=py_0
- - tifffile=2021.2.1=pyhd8ed1ab_0
- - toml=0.10.2=pyhd8ed1ab_0
- - toolz=0.11.1=py_0
- - tqdm=4.56.2=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.3=pyhd8ed1ab_0
- - wcwidth=0.2.5=pyh9f0ad1d_2
- - webencodings=0.5.1=py_1
- - wheel=0.36.2=pyhd3deb0d_0
- - xarray=0.16.2=pyhd8ed1ab_0
- - zict=2.0.0=py_0
- - zipp=3.4.0=py_0
+ - appdirs=1.4.4=pyh9f0ad1d_0
+ - async_generator=1.10=py_0
+ - attrs=20.3.0=pyhd3deb0d_0
+ - babel=2.9.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.3.0=pyh44b312d_0
+ - cachetools=4.2.1=pyhd8ed1ab_0
+ - click=7.1.2=pyh9f0ad1d_0
+ - cloudpickle=1.6.0=py_0
+ - colorcet=2.0.6=pyhd8ed1ab_0
+ - cycler=0.10.0=py_2
+ - dask-core=2021.2.0=pyhd8ed1ab_0
+ - dask=2021.2.0=pyhd8ed1ab_0
+ - dataclasses=0.7=pyhb2cacf7_7
+ - datashader=0.12.0=pyhd3deb0d_0
+ - datashape=0.5.4=py_1
+ - decorator=4.4.2=py_0
+ - defusedxml=0.6.0=py_0
+ - entrypoints=0.3=pyhd8ed1ab_1003
+ - frozendict=1.2=pyh9f0ad1d_3
+ - fsspec=0.8.7=pyhd8ed1ab_0
+ - heapdict=1.0.1=py_0
+ - holoviews=1.14.1=pyhd3deb0d_0
+ - html5lib=1.1=pyh9f0ad1d_0
+ - hvplot=0.7.0=pyhd3deb0d_0
+ - idna=2.10=pyh9f0ad1d_0
+ - imageio=2.9.0=py_0
+ - importlib_metadata=3.7.0=hd8ed1ab_0
+ - importnb=0.7.0=pyhd8ed1ab_0
+ - iniconfig=1.1.1=pyh9f0ad1d_0
+ - ipycytoscape=1.2.0=pyhd8ed1ab_0
+ - ipython_genutils=0.2.0=py_1
+ - ipywidgets=7.6.3=pyhd3deb0d_0
+ - isodate=0.6.0=py_1
+ - jinja2=2.11.3=pyh44b312d_0
+ - json5=0.9.5=pyh9f0ad1d_0
+ - jsonschema=3.2.0=py_2
+ - jupyter-packaging=0.7.12=pyhd8ed1ab_0
+ - jupyter_client=6.1.11=pyhd8ed1ab_1
+ - jupyterlab=3.0.9=pyhd8ed1ab_0
+ - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
+ - jupyterlab_server=2.3.0=pyhd8ed1ab_0
+ - jupyterlab_widgets=1.0.0=pyhd8ed1ab_1
+ - locket=0.2.0=py_2
+ - markdown=3.3.4=pyhd8ed1ab_0
+ - more-itertools=8.7.0=pyhd8ed1ab_0
+ - multipledispatch=0.6.0=py_0
+ - nbclassic=0.2.6=pyhd8ed1ab_0
+ - nbclient=0.5.3=pyhd8ed1ab_0
+ - nbformat=5.1.2=pyhd8ed1ab_1
+ - nest-asyncio=1.4.3=pyhd8ed1ab_0
+ - networkx=2.5=py_0
+ - olefile=0.46=pyh9f0ad1d_1
+ - owlrl=5.2.1=py_0
+ - packaging=20.9=pyh44b312d_0
+ - pandocfilters=1.4.2=py_1
+ - panel=0.10.3=pyhd8ed1ab_0
+ - param=1.10.1=pyhd3deb0d_0
+ - parso=0.8.1=pyhd8ed1ab_0
+ - partd=1.1.0=py_0
+ - pickleshare=0.7.5=py_1003
+ - pip=21.0.1=pyhd8ed1ab_0
+ - pooch=1.3.0=pyhd8ed1ab_0
+ - prometheus_client=0.9.0=pyhd3deb0d_0
+ - prompt-toolkit=3.0.16=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.8.0=pyhd8ed1ab_0
+ - pyld=2.0.3=pyh9f0ad1d_0
+ - pyopenssl=20.0.1=pyhd8ed1ab_0
+ - pyparsing=2.4.7=pyh9f0ad1d_0
+ - pyshacl=0.14.3=pyhd8ed1ab_0
+ - pytest-cov=2.11.1=pyh44b312d_0
+ - python-dateutil=2.8.1=py_0
+ - python_abi=3.7=1_cp37m
+ - pytz=2021.1=pyhd8ed1ab_0
+ - pyviz_comms=2.0.1=pyhd3deb0d_0
+ - requests=2.25.1=pyhd3deb0d_0
+ - requests_cache=0.4.13=py_0
+ - send2trash=1.5.0=py_0
+ - six=1.15.0=pyh9f0ad1d_0
+ - sortedcontainers=2.3.0=pyhd8ed1ab_0
+ - tblib=1.6.0=py_0
+ - testpath=0.4.4=py_0
+ - tifffile=2021.2.26=pyhd8ed1ab_0
+ - toml=0.10.2=pyhd8ed1ab_0
+ - toolz=0.11.1=py_0
+ - tqdm=4.58.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.3=pyhd8ed1ab_0
+ - wcwidth=0.2.5=pyh9f0ad1d_2
+ - webencodings=0.5.1=py_1
+ - wheel=0.36.2=pyhd3deb0d_0
+ - xarray=0.17.0=pyhd8ed1ab_0
+ - zict=2.0.0=py_0
+ - zipp=3.4.0=py_0
unix:
- - libblas=3.9.0=8_openblas
- - libcblas=3.9.0=8_openblas
- - liblapack=3.9.0=8_openblas
- - pexpect=4.8.0=pyh9f0ad1d_2
- - ptyprocess=0.7.0=pyhd3deb0d_0
+ - libblas=3.9.0=8_openblas
+ - libcblas=3.9.0=8_openblas
+ - liblapack=3.9.0=8_openblas
+ - 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
- - anyio=2.1.0=py37h89c1867_0
- - argon2-cffi=20.1.0=py37h5e8e339_2
- - blosc=1.21.0=h9c3ff4c_0
- - bokeh=2.2.3=py37h89c1867_0
- - brotli=1.0.9=h9c3ff4c_4
- - brotlipy=0.7.0=py37h5e8e339_1001
- - brunsli=0.1=h9c3ff4c_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.4=py37h5e8e339_0
- - cryptography=3.4.4=py37hf1a17b8_0
- - cytoolz=0.11.0=py37h5e8e339_3
- - distributed=2021.2.0=py37h89c1867_0
- - freetype=2.10.4=h0708190_1
- - giflib=5.2.1=h36c2ea0_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.20.0=py37h888b3d9_2
- - jedi=0.18.0=py37h89c1867_2
- - jpeg=9d=h36c2ea0_0
- - jupyter_core=4.7.1=py37h89c1867_0
- - jupyter_server=1.3.0=py37h89c1867_0
- - jxrlib=1.1=h7f98852_2
- - keepalive=0.5=py37h89c1867_5
- - kiwisolver=1.3.1=py37h2527ec5_1
- - lcms2=2.12=hddcbb42_0
- - ld_impl_linux-64=2.35.1=hea4e1c9_2
- - lerc=2.2.1=h9c3ff4c_0
- - libaec=1.0.4=h9c3ff4c_1
- - 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.12=pthreads_h4812303_1
- - libpng=1.6.37=h21135ba_2
- - libsodium=1.0.18=h36c2ea0_1
- - libstdcxx-ng=9.3.0=h6de172a_18
- - libtiff=4.2.0=hdc55705_0
- - libuv=1.40.0=h7f98852_0
- - libwebp-base=1.2.0=h7f98852_0
- - libxml2=2.9.10=h72842e0_3
- - libxslt=1.1.33=h15afd5d_2
- - libzopfli=1.0.3=h9c3ff4c_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.4=py37h0c9df89_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.20.1=py37haa41c4c_0
- - openjpeg=2.4.0=hf7af979_0
- - openssl=1.1.1i=h7f98852_0
- - pandas=1.2.2=py37hdc94413_0
- - pandoc=2.11.4=h7f98852_0
- - pillow=8.1.0=py37h4600e1f_2
- - 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.2=py37h89c1867_0
- - python=3.7.9=hffdb5ce_0_cpython
- - pywavelets=1.1.1=py37h902c9e0_3
- - pyyaml=5.4.1=py37h5e8e339_0
- - pyzmq=22.0.1=py37h499b945_0
- - rdflib-jsonld=0.5.0=py37h89c1867_2
- - rdflib=5.0.0=py37h89c1867_3
- - readline=8.0=he28a2e2_2
- - 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
- - sniffio=1.2.0=py37h89c1867_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=h21135ba_1
- - tornado=6.1=py37h5e8e339_1
- - widgetsnbextension=3.5.1=py37h89c1867_4
- - xz=5.2.5=h516909a_1
- - yaml=0.2.5=h516909a_0
- - zeromq=4.3.4=h9c3ff4c_0
- - zfp=0.5.5=h9c3ff4c_4
- - zlib=1.2.11=h516909a_1010
- - zstd=1.4.8=ha95c52a_1
+ - _libgcc_mutex=0.1=conda_forge
+ - _openmp_mutex=4.5=1_gnu
+ - anyio=2.2.0=py37h89c1867_0
+ - argon2-cffi=20.1.0=py37h5e8e339_2
+ - blosc=1.21.0=h9c3ff4c_0
+ - bokeh=2.3.0=py37h89c1867_0
+ - brotli=1.0.9=h9c3ff4c_4
+ - brotlipy=0.7.0=py37h5e8e339_1001
+ - brunsli=0.1=h9c3ff4c_0
+ - bzip2=1.0.8=h7f98852_4
+ - ca-certificates=2020.12.5=ha878542_0
+ - certifi=2020.12.5=py37h89c1867_1
+ - cffi=1.14.5=py37hc58025e_0
+ - chardet=4.0.0=py37h89c1867_1
+ - charls=2.2.0=h9c3ff4c_0
+ - coverage=5.5=py37h5e8e339_0
+ - cryptography=3.4.4=py37hf1a17b8_0
+ - cytoolz=0.11.0=py37h5e8e339_3
+ - distributed=2021.2.0=py37h89c1867_0
+ - freetype=2.10.4=h0708190_1
+ - giflib=5.2.1=h36c2ea0_2
+ - icu=68.1=h58526e2_0
+ - imagecodecs=2021.1.28=py37h1985380_0
+ - importlib-metadata=3.7.0=py37h89c1867_0
+ - importlib_resources=5.1.1=py37h89c1867_0
+ - ipykernel=5.5.0=py37h888b3d9_1
+ - ipython=7.21.0=py37h888b3d9_0
+ - jedi=0.18.0=py37h89c1867_2
+ - jpeg=9d=h36c2ea0_0
+ - jupyter_core=4.7.1=py37h89c1867_0
+ - jupyter_server=1.4.1=py37h89c1867_0
+ - jxrlib=1.1=h7f98852_2
+ - keepalive=0.5=py37h89c1867_5
+ - kiwisolver=1.3.1=py37h2527ec5_1
+ - lcms2=2.12=hddcbb42_0
+ - ld_impl_linux-64=2.35.1=hea4e1c9_2
+ - lerc=2.2.1=h9c3ff4c_0
+ - libaec=1.0.4=h9c3ff4c_1
+ - 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.12=pthreads_h4812303_1
+ - libpng=1.6.37=h21135ba_2
+ - libsodium=1.0.18=h36c2ea0_1
+ - libstdcxx-ng=9.3.0=h6de172a_18
+ - libtiff=4.2.0=hdc55705_0
+ - libuv=1.41.0=h7f98852_0
+ - libwebp-base=1.2.0=h7f98852_0
+ - libxml2=2.9.10=h72842e0_3
+ - libxslt=1.1.33=h15afd5d_2
+ - libzopfli=1.0.3=h9c3ff4c_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.4=py37h0c9df89_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=h8b53aa1_3
+ - notebook=6.2.0=py37h89c1867_0
+ - numba=0.52.0=py37hdc94413_0
+ - numpy=1.20.1=py37haa41c4c_0
+ - openjpeg=2.4.0=hf7af979_0
+ - openssl=1.1.1j=h7f98852_0
+ - pandas=1.2.2=py37hdc94413_0
+ - pandoc=2.11.4=h7f98852_0
+ - pillow=8.1.0=py37h4600e1f_2
+ - 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.2=py37h89c1867_0
+ - python=3.7.10=hffdb5ce_100_cpython
+ - pywavelets=1.1.1=py37h902c9e0_3
+ - pyyaml=5.4.1=py37h5e8e339_0
+ - pyzmq=22.0.3=py37h336d617_1
+ - rdflib-jsonld=0.5.0=py37h89c1867_2
+ - rdflib=5.0.0=py37h89c1867_3
+ - readline=8.0=he28a2e2_2
+ - 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
+ - sniffio=1.2.0=py37h89c1867_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=h21135ba_1
+ - tornado=6.1=py37h5e8e339_1
+ - widgetsnbextension=3.5.1=py37h89c1867_4
+ - xz=5.2.5=h516909a_1
+ - yaml=0.2.5=h516909a_0
+ - zeromq=4.3.4=h9c3ff4c_0
+ - zfp=0.5.5=h9c3ff4c_4
+ - zlib=1.2.11=h516909a_1010
+ - zstd=1.4.8=ha95c52a_1
osx-64:
- - anyio=2.1.0=py37hf985489_0
- - 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.4=py37hf967b71_0
- - cryptography=3.4.4=py37ha1e1f9f_0
- - cytoolz=0.11.0=py37hf967b71_3
- - distributed=2021.2.0=py37hf985489_0
- - 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.20.0=py37he01cfaa_2
- - jedi=0.18.0=py37hf985489_2
- - jpeg=9d=hbcb3906_0
- - jupyter_core=4.7.1=py37hf985489_0
- - jupyter_server=1.3.0=py37hf985489_0
- - jxrlib=1.1=h35c211d_2
- - keepalive=0.5=py37hf985489_5
- - kiwisolver=1.3.1=py37h70f7d40_1
- - lcms2=2.12=h577c468_0
- - lerc=2.2.1=h046ec9c_0
- - libaec=1.0.4=h046ec9c_1
- - libcxx=11.0.1=habf9029_0
- - libdeflate=1.7=h35c211d_5
- - libffi=3.3=h046ec9c_2
- - libgfortran5=9.3.0=h6c81a4c_17
- - libgfortran=5.0.0=9_3_0_h6c81a4c_17
- - libiconv=1.16=haf1e3a3_0
- - libllvm10=10.0.1=h009f743_3
- - 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.2.0=hbcf498f_0
- - 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.4=py37haa7e288_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.20.1=py37ha9839cc_0
- - openjpeg=2.4.0=h6cbf5cd_0
- - openssl=1.1.1i=h35c211d_0
- - pandas=1.2.2=py37h7d02bce_0
- - pandoc=2.11.4=h35c211d_0
- - pillow=8.1.0=py37hd722d6e_2
- - 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.2=py37hf985489_0
- - python=3.7.9=h6c3b2c9_0_cpython
- - pywavelets=1.1.1=py37h37391d0_3
- - pyyaml=5.4.1=py37hf967b71_0
- - pyzmq=22.0.1=py37hf4687c3_0
- - rdflib-jsonld=0.5.0=py37hf985489_2
- - rdflib=5.0.0=py37hf985489_3
- - readline=8.0=h0678c8f_2
- - scikit-image=0.18.1=py37h010c265_0
- - scipy=1.6.0=py37hc22aa43_0
- - setuptools=49.6.0=py37hf985489_3
- - snappy=1.1.8=hb1e8313_3
- - sniffio=1.2.0=py37hf985489_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.4=h1c7c35f_0
- - zfp=0.5.5=h046ec9c_4
- - zlib=1.2.11=h7795811_1010
- - zstd=1.4.8=hf387650_1
+ - anyio=2.2.0=py37hf985489_0
+ - appnope=0.1.2=py37hf985489_1
+ - argon2-cffi=20.1.0=py37hf967b71_2
+ - blosc=1.21.0=h046ec9c_0
+ - bokeh=2.3.0=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.5=py37h4d371b4_0
+ - chardet=4.0.0=py37hf985489_1
+ - charls=2.2.0=h046ec9c_0
+ - coverage=5.5=py37h271585c_0
+ - cryptography=3.4.4=py37ha1e1f9f_0
+ - cytoolz=0.11.0=py37hf967b71_3
+ - distributed=2021.2.0=py37hf985489_0
+ - freetype=2.10.4=h4cff582_1
+ - giflib=5.2.1=hbcb3906_2
+ - icu=68.1=h74dc148_0
+ - imagecodecs=2021.1.28=py37h9f08f5f_0
+ - importlib-metadata=3.7.0=py37hf985489_0
+ - importlib_resources=5.1.1=py37hf985489_0
+ - ipykernel=5.5.0=py37he01cfaa_1
+ - ipython=7.21.0=py37he01cfaa_0
+ - jedi=0.18.0=py37hf985489_2
+ - jpeg=9d=hbcb3906_0
+ - jupyter_core=4.7.1=py37hf985489_0
+ - jupyter_server=1.4.1=py37hf985489_0
+ - jxrlib=1.1=h35c211d_2
+ - keepalive=0.5=py37hf985489_5
+ - kiwisolver=1.3.1=py37h70f7d40_1
+ - lcms2=2.12=h577c468_0
+ - lerc=2.2.1=h046ec9c_0
+ - libaec=1.0.4=h046ec9c_1
+ - libcxx=11.0.1=habf9029_0
+ - libdeflate=1.7=h35c211d_5
+ - libffi=3.3=h046ec9c_2
+ - libgfortran5=9.3.0=h6c81a4c_19
+ - libgfortran=5.0.0=9_3_0_h6c81a4c_19
+ - libiconv=1.16=haf1e3a3_0
+ - libllvm10=10.0.1=h009f743_3
+ - 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.41.0=hbcf498f_0
+ - libwebp-base=1.2.0=hbcf498f_0
+ - 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.4=py37haa7e288_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=hf294227_3
+ - notebook=6.2.0=py37hf985489_0
+ - numba=0.52.0=py37h010c265_0
+ - numpy=1.20.1=py37ha9839cc_0
+ - openjpeg=2.4.0=h6cbf5cd_0
+ - openssl=1.1.1j=hbcf498f_0
+ - pandas=1.2.2=py37h7d02bce_0
+ - pandoc=2.11.4=h35c211d_0
+ - pillow=8.1.0=py37hd722d6e_2
+ - 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.2=py37hf985489_0
+ - python=3.7.10=h7728216_100_cpython
+ - pywavelets=1.1.1=py37h37391d0_3
+ - pyyaml=5.4.1=py37hf967b71_0
+ - pyzmq=22.0.3=py37h8f778e5_1
+ - rdflib-jsonld=0.5.0=py37hf985489_2
+ - rdflib=5.0.0=py37hf985489_3
+ - readline=8.0=h0678c8f_2
+ - scikit-image=0.18.1=py37h010c265_0
+ - scipy=1.6.0=py37hc22aa43_0
+ - setuptools=49.6.0=py37hf985489_3
+ - snappy=1.1.8=hb1e8313_3
+ - sniffio=1.2.0=py37hf985489_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.4=h1c7c35f_0
+ - zfp=0.5.5=h046ec9c_4
+ - zlib=1.2.11=h7795811_1010
+ - zstd=1.4.8=hf387650_1
win-64:
- - anyio=2.1.0=py37h03978a9_0
- - argon2-cffi=20.1.0=py37hcc03f2d_2
- - atomicwrites=1.4.0=pyh9f0ad1d_0
- - 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.4=py37hcc03f2d_0
- - cryptography=3.4.4=py37h65266a2_0
- - cytoolz=0.11.0=py37hcc03f2d_3
- - distributed=2021.2.0=py37h03978a9_0
- - 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.20.0=py37heaed05f_2
- - jedi=0.18.0=py37h03978a9_2
- - jpeg=9d=h8ffe710_0
- - jupyter_core=4.7.1=py37h03978a9_0
- - jupyter_server=1.3.0=py37h03978a9_0
- - jxrlib=1.1=h8ffe710_2
- - keepalive=0.5=py37h03978a9_5
- - kiwisolver=1.3.1=py37h8c56517_1
- - lcms2=2.12=h2a16943_0
- - lerc=2.2.1=h0e60522_0
- - libaec=1.0.4=h39d44d4_1
- - libblas=3.9.0=8_mkl
- - libcblas=3.9.0=8_mkl
- - libdeflate=1.7=h8ffe710_5
- - libiconv=1.16=he774522_0
- - liblapack=3.9.0=8_mkl
- - libpng=1.6.37=h1d00b33_2
- - libsodium=1.0.18=h8d14728_1
- - libtiff=4.2.0=hc10be44_0
- - libwebp-base=1.2.0=h8ffe710_0
- - 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=py37hcc03f2d_3
- - matplotlib-base=3.3.4=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
- - 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.20.1=py37hd20adf4_0
- - openjpeg=2.4.0=h48faf41_0
- - openssl=1.1.1i=h8ffe710_0
- - pandas=1.2.2=py37h08fd248_0
- - pandoc=2.11.4=h8ffe710_0
- - pillow=8.1.0=py37h96663a1_2
- - 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.2=py37h03978a9_0
- - 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.4.1=py37hcc03f2d_0
- - pyzmq=22.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
- - sniffio=1.2.0=py37h03978a9_1
- - 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_3
- - vs2015_runtime=14.28.29325=h5e1d092_3
- - widgetsnbextension=3.5.1=py37h03978a9_4
- - win_inet_pton=1.1.0=py37h03978a9_2
- - wincertstore=0.2=py37h03978a9_1006
- - winpty=0.4.3=4
- - 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
+ - anyio=2.2.0=py37h03978a9_0
+ - argon2-cffi=20.1.0=py37hcc03f2d_2
+ - atomicwrites=1.4.0=pyh9f0ad1d_0
+ - blosc=1.21.0=h0e60522_0
+ - bokeh=2.3.0=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.5=py37hd8e9650_0
+ - chardet=4.0.0=py37h03978a9_1
+ - charls=2.2.0=h39d44d4_0
+ - colorama=0.4.4=pyh9f0ad1d_0
+ - coverage=5.5=py37hcc03f2d_0
+ - cryptography=3.4.4=py37h65266a2_0
+ - cytoolz=0.11.0=py37hcc03f2d_3
+ - distributed=2021.2.0=py37h03978a9_0
+ - freetype=2.10.4=h546665d_1
+ - giflib=5.2.1=h8d14728_2
+ - imagecodecs=2021.1.28=py37hb664a41_0
+ - importlib-metadata=3.7.0=py37h03978a9_0
+ - importlib_resources=5.1.1=py37h03978a9_0
+ - intel-openmp=2020.3=h57928b3_311
+ - ipykernel=5.5.0=py37heaed05f_1
+ - ipython=7.21.0=py37heaed05f_0
+ - jedi=0.18.0=py37h03978a9_2
+ - jpeg=9d=h8ffe710_0
+ - jupyter_core=4.7.1=py37h03978a9_0
+ - jupyter_server=1.4.1=py37h03978a9_0
+ - jxrlib=1.1=h8ffe710_2
+ - keepalive=0.5=py37h03978a9_5
+ - kiwisolver=1.3.1=py37h8c56517_1
+ - lcms2=2.12=h2a16943_0
+ - lerc=2.2.1=h0e60522_0
+ - libaec=1.0.4=h39d44d4_1
+ - libblas=3.9.0=8_mkl
+ - libcblas=3.9.0=8_mkl
+ - libdeflate=1.7=h8ffe710_5
+ - libiconv=1.16=he774522_0
+ - liblapack=3.9.0=8_mkl
+ - libpng=1.6.37=h1d00b33_2
+ - libsodium=1.0.18=h8d14728_1
+ - libtiff=4.2.0=hc10be44_0
+ - libwebp-base=1.2.0=h8ffe710_0
+ - 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=py37hcc03f2d_3
+ - matplotlib-base=3.3.4=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
+ - nbconvert=6.0.7=py37h03978a9_3
+ - nodejs=12.19.0=h57928b3_3
+ - notebook=6.2.0=py37h03978a9_0
+ - numba=0.52.0=py37h08fd248_0
+ - numpy=1.20.1=py37hd20adf4_0
+ - openjpeg=2.4.0=h48faf41_0
+ - openssl=1.1.1j=h8ffe710_0
+ - pandas=1.2.2=py37h08fd248_0
+ - pandoc=2.11.4=h8ffe710_0
+ - pillow=8.1.0=py37h96663a1_2
+ - 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.2=py37h03978a9_0
+ - python=3.7.10=h7840368_100_cpython
+ - pywavelets=1.1.1=py37hda49f71_3
+ - pywin32=300=py37hcc03f2d_0
+ - pywinpty=0.5.7=py37hc8dfbb8_1
+ - pyyaml=5.4.1=py37hcc03f2d_0
+ - pyzmq=22.0.3=py37hcce574b_1
+ - 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
+ - sniffio=1.2.0=py37h03978a9_1
+ - 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_3
+ - vs2015_runtime=14.28.29325=h5e1d092_3
+ - widgetsnbextension=3.5.1=py37h03978a9_4
+ - win_inet_pton=1.1.0=py37h03978a9_2
+ - wincertstore=0.2=py37h03978a9_1006
+ - winpty=0.4.3=4
+ - xz=5.2.5=h62dcd97_1
+ - yaml=0.2.5=he774522_0
+ - zeromq=4.3.4=h0e60522_0
+ - zfp=0.5.5=h0e60522_4
+ - zlib=1.2.11=h62dcd97_1010
+ - zstd=1.4.8=h4e2f164_1
qa:
locked: true
env_spec_hash: 0fc8232ea04f9408db0d00c84810e209edbcfd4b
platforms:
- - linux-64
- - osx-64
- - win-64
+ - linux-64
+ - osx-64
+ - win-64
packages:
all:
- - appdirs=1.4.4=pyh9f0ad1d_0
- - async_generator=1.10=py_0
- - attrs=20.3.0=pyhd3deb0d_0
- - babel=2.9.0=pyhd3deb0d_0
- - backcall=0.2.0=pyh9f0ad1d_0
- - backports.functools_lru_cache=1.6.1=py_0
- - backports=1.0=py_2
- - black=20.8b1=py_1
- - bleach=3.3.0=pyh44b312d_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_genutils=0.2.0=py_1
- - isort=5.7.0=pyhd8ed1ab_0
- - jinja2=2.11.3=pyh44b312d_0
- - json5=0.9.5=pyh9f0ad1d_0
- - jsonschema=3.2.0=py_2
- - jupyter_client=6.1.11=pyhd8ed1ab_1
- - jupyterlab=3.0.7=pyhd8ed1ab_0
- - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
- - jupyterlab_server=2.2.0=pyhd8ed1ab_0
- - mccabe=0.6.1=py_1
- - nbclassic=0.2.6=pyhd8ed1ab_0
- - nbclient=0.5.2=pyhd8ed1ab_0
- - nbformat=5.1.2=pyhd8ed1ab_1
- - nest-asyncio=1.4.3=pyhd8ed1ab_0
- - packaging=20.9=pyh44b312d_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
- - prometheus_client=0.9.0=pyhd3deb0d_0
- - prompt-toolkit=3.0.16=pyha770c72_0
- - pycodestyle=2.6.0=pyh9f0ad1d_0
- - pycparser=2.20=pyh9f0ad1d_2
- - pyflakes=2.2.0=pyh9f0ad1d_0
- - pygments=2.7.4=pyhd8ed1ab_0
- - pyopenssl=20.0.1=pyhd8ed1ab_0
- - pyparsing=2.4.7=pyh9f0ad1d_0
- - python-dateutil=2.8.1=py_0
- - python_abi=3.7=1_cp37m
- - pytz=2021.1=pyhd8ed1ab_0
- - requests=2.25.1=pyhd3deb0d_0
- - send2trash=1.5.0=py_0
- - six=1.15.0=pyh9f0ad1d_0
- - testpath=0.4.4=py_0
- - toml=0.10.2=pyhd8ed1ab_0
- - traitlets=5.0.5=py_0
- - typing_extensions=3.7.4.3=py_0
- - urllib3=1.26.3=pyhd8ed1ab_0
- - wcwidth=0.2.5=pyh9f0ad1d_2
- - webencodings=0.5.1=py_1
- - zipp=3.4.0=py_0
+ - appdirs=1.4.4=pyh9f0ad1d_0
+ - async_generator=1.10=py_0
+ - attrs=20.3.0=pyhd3deb0d_0
+ - babel=2.9.0=pyhd3deb0d_0
+ - backcall=0.2.0=pyh9f0ad1d_0
+ - backports.functools_lru_cache=1.6.1=py_0
+ - backports=1.0=py_2
+ - black=20.8b1=py_1
+ - bleach=3.3.0=pyh44b312d_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.7.0=hd8ed1ab_0
+ - ipython_genutils=0.2.0=py_1
+ - isort=5.7.0=pyhd8ed1ab_0
+ - jinja2=2.11.3=pyh44b312d_0
+ - json5=0.9.5=pyh9f0ad1d_0
+ - jsonschema=3.2.0=py_2
+ - jupyter-packaging=0.7.12=pyhd8ed1ab_0
+ - jupyter_client=6.1.11=pyhd8ed1ab_1
+ - jupyterlab=3.0.9=pyhd8ed1ab_0
+ - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0
+ - jupyterlab_server=2.3.0=pyhd8ed1ab_0
+ - mccabe=0.6.1=py_1
+ - nbclassic=0.2.6=pyhd8ed1ab_0
+ - nbclient=0.5.3=pyhd8ed1ab_0
+ - nbformat=5.1.2=pyhd8ed1ab_1
+ - nest-asyncio=1.4.3=pyhd8ed1ab_0
+ - packaging=20.9=pyh44b312d_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=21.0.1=pyhd8ed1ab_0
+ - prometheus_client=0.9.0=pyhd3deb0d_0
+ - prompt-toolkit=3.0.16=pyha770c72_0
+ - pycodestyle=2.6.0=pyh9f0ad1d_0
+ - pycparser=2.20=pyh9f0ad1d_2
+ - pyflakes=2.2.0=pyh9f0ad1d_0
+ - pygments=2.8.0=pyhd8ed1ab_0
+ - pyopenssl=20.0.1=pyhd8ed1ab_0
+ - pyparsing=2.4.7=pyh9f0ad1d_0
+ - python-dateutil=2.8.1=py_0
+ - python_abi=3.7=1_cp37m
+ - pytz=2021.1=pyhd8ed1ab_0
+ - requests=2.25.1=pyhd3deb0d_0
+ - send2trash=1.5.0=py_0
+ - six=1.15.0=pyh9f0ad1d_0
+ - testpath=0.4.4=py_0
+ - toml=0.10.2=pyhd8ed1ab_0
+ - traitlets=5.0.5=py_0
+ - typing_extensions=3.7.4.3=py_0
+ - urllib3=1.26.3=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
+ - 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
- - anyio=2.1.0=py37h89c1867_0
- - argon2-cffi=20.1.0=py37h5e8e339_2
- - brotlipy=0.7.0=py37h5e8e339_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.4.4=py37hf1a17b8_0
- - icu=68.1=h58526e2_0
- - importlib-metadata=3.4.0=py37h89c1867_0
- - ipykernel=5.4.2=py37h888b3d9_0
- - ipython=7.20.0=py37h888b3d9_2
- - jedi=0.18.0=py37h89c1867_2
- - jupyter_core=4.7.1=py37h89c1867_0
- - jupyter_server=1.3.0=py37h89c1867_0
- - ld_impl_linux-64=2.35.1=hea4e1c9_2
- - libffi=3.3=h58526e2_2
- - libgcc-ng=9.3.0=h2828fa1_18
- - libgomp=9.3.0=h2828fa1_18
- - libsodium=1.0.18=h36c2ea0_1
- - libstdcxx-ng=9.3.0=h6de172a_18
- - libuv=1.40.0=h7f98852_0
- - markupsafe=1.1.1=py37h5e8e339_3
- - mistune=0.8.4=py37h5e8e339_1003
- - mypy_extensions=0.4.3=py37h89c1867_3
- - nbconvert=6.0.7=py37h89c1867_3
- - ncurses=6.2=h58526e2_4
- - nodejs=12.19.0=hfa01f41_2
- - notebook=6.2.0=py37h89c1867_0
- - openssl=1.1.1i=h7f98852_0
- - pandoc=2.11.4=h7f98852_0
- - pyrsistent=0.17.3=py37h5e8e339_2
- - pysocks=1.7.1=py37h89c1867_3
- - python=3.7.9=hffdb5ce_0_cpython
- - pyzmq=22.0.1=py37h499b945_0
- - readline=8.0=he28a2e2_2
- - regex=2020.11.13=py37h5e8e339_1
- - setuptools=49.6.0=py37h89c1867_3
- - sniffio=1.2.0=py37h89c1867_1
- - sqlite=3.34.0=h74cdb3f_0
- - terminado=0.9.2=py37h89c1867_0
- - tk=8.6.10=h21135ba_1
- - tornado=6.1=py37h5e8e339_1
- - typed-ast=1.4.2=py37h5e8e339_0
- - xz=5.2.5=h516909a_1
- - zeromq=4.3.4=h9c3ff4c_0
- - zlib=1.2.11=h516909a_1010
+ - _libgcc_mutex=0.1=conda_forge
+ - _openmp_mutex=4.5=1_gnu
+ - anyio=2.2.0=py37h89c1867_0
+ - argon2-cffi=20.1.0=py37h5e8e339_2
+ - brotlipy=0.7.0=py37h5e8e339_1001
+ - ca-certificates=2020.12.5=ha878542_0
+ - certifi=2020.12.5=py37h89c1867_1
+ - cffi=1.14.5=py37hc58025e_0
+ - chardet=4.0.0=py37h89c1867_1
+ - cryptography=3.4.4=py37hf1a17b8_0
+ - icu=68.1=h58526e2_0
+ - importlib-metadata=3.7.0=py37h89c1867_0
+ - ipykernel=5.5.0=py37h888b3d9_1
+ - ipython=7.21.0=py37h888b3d9_0
+ - jedi=0.18.0=py37h89c1867_2
+ - jupyter_core=4.7.1=py37h89c1867_0
+ - jupyter_server=1.4.1=py37h89c1867_0
+ - ld_impl_linux-64=2.35.1=hea4e1c9_2
+ - libffi=3.3=h58526e2_2
+ - libgcc-ng=9.3.0=h2828fa1_18
+ - libgomp=9.3.0=h2828fa1_18
+ - libsodium=1.0.18=h36c2ea0_1
+ - libstdcxx-ng=9.3.0=h6de172a_18
+ - libuv=1.41.0=h7f98852_0
+ - markupsafe=1.1.1=py37h5e8e339_3
+ - mistune=0.8.4=py37h5e8e339_1003
+ - mypy_extensions=0.4.3=py37h89c1867_3
+ - nbconvert=6.0.7=py37h89c1867_3
+ - ncurses=6.2=h58526e2_4
+ - nodejs=12.19.0=h8b53aa1_3
+ - notebook=6.2.0=py37h89c1867_0
+ - openssl=1.1.1j=h7f98852_0
+ - pandoc=2.11.4=h7f98852_0
+ - pyrsistent=0.17.3=py37h5e8e339_2
+ - pysocks=1.7.1=py37h89c1867_3
+ - python=3.7.10=hffdb5ce_100_cpython
+ - pyzmq=22.0.3=py37h336d617_1
+ - readline=8.0=he28a2e2_2
+ - regex=2020.11.13=py37h5e8e339_1
+ - setuptools=49.6.0=py37h89c1867_3
+ - sniffio=1.2.0=py37h89c1867_1
+ - sqlite=3.34.0=h74cdb3f_0
+ - terminado=0.9.2=py37h89c1867_0
+ - tk=8.6.10=h21135ba_1
+ - tornado=6.1=py37h5e8e339_1
+ - typed-ast=1.4.2=py37h5e8e339_0
+ - xz=5.2.5=h516909a_1
+ - zeromq=4.3.4=h9c3ff4c_0
+ - zlib=1.2.11=h516909a_1010
osx-64:
- - anyio=2.1.0=py37hf985489_0
- - appnope=0.1.2=py37hf985489_1
- - argon2-cffi=20.1.0=py37hf967b71_2
- - 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
- - cryptography=3.4.4=py37ha1e1f9f_0
- - icu=68.1=h74dc148_0
- - importlib-metadata=3.4.0=py37hf985489_0
- - ipykernel=5.4.2=py37he01cfaa_0
- - ipython=7.20.0=py37he01cfaa_2
- - jedi=0.18.0=py37hf985489_2
- - jupyter_core=4.7.1=py37hf985489_0
- - jupyter_server=1.3.0=py37hf985489_0
- - libcxx=11.0.1=habf9029_0
- - libffi=3.3=h046ec9c_2
- - libsodium=1.0.18=hbcb3906_1
- - libuv=1.40.0=h35c211d_0
- - markupsafe=1.1.1=py37hf967b71_3
- - mistune=0.8.4=py37hf967b71_1003
- - mypy_extensions=0.4.3=py37hf985489_3
- - nbconvert=6.0.7=py37hf985489_3
- - ncurses=6.2=h2e338ed_4
- - nodejs=12.19.0=h49b9f75_2
- - notebook=6.2.0=py37hf985489_0
- - openssl=1.1.1i=h35c211d_0
- - pandoc=2.11.4=h35c211d_0
- - pyrsistent=0.17.3=py37hf967b71_2
- - pysocks=1.7.1=py37hf985489_3
- - python=3.7.9=h6c3b2c9_0_cpython
- - pyzmq=22.0.1=py37hf4687c3_0
- - readline=8.0=h0678c8f_2
- - regex=2020.11.13=py37hf967b71_1
- - setuptools=49.6.0=py37hf985489_3
- - sniffio=1.2.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
- - typed-ast=1.4.2=py37hf967b71_0
- - xz=5.2.5=haf1e3a3_1
- - zeromq=4.3.4=h1c7c35f_0
- - zlib=1.2.11=h7795811_1010
+ - anyio=2.2.0=py37hf985489_0
+ - appnope=0.1.2=py37hf985489_1
+ - argon2-cffi=20.1.0=py37hf967b71_2
+ - brotlipy=0.7.0=py37hf967b71_1001
+ - ca-certificates=2020.12.5=h033912b_0
+ - certifi=2020.12.5=py37hf985489_1
+ - cffi=1.14.5=py37h4d371b4_0
+ - chardet=4.0.0=py37hf985489_1
+ - cryptography=3.4.4=py37ha1e1f9f_0
+ - icu=68.1=h74dc148_0
+ - importlib-metadata=3.7.0=py37hf985489_0
+ - ipykernel=5.5.0=py37he01cfaa_1
+ - ipython=7.21.0=py37he01cfaa_0
+ - jedi=0.18.0=py37hf985489_2
+ - jupyter_core=4.7.1=py37hf985489_0
+ - jupyter_server=1.4.1=py37hf985489_0
+ - libcxx=11.0.1=habf9029_0
+ - libffi=3.3=h046ec9c_2
+ - libsodium=1.0.18=hbcb3906_1
+ - libuv=1.41.0=hbcf498f_0
+ - markupsafe=1.1.1=py37hf967b71_3
+ - mistune=0.8.4=py37hf967b71_1003
+ - mypy_extensions=0.4.3=py37hf985489_3
+ - nbconvert=6.0.7=py37hf985489_3
+ - ncurses=6.2=h2e338ed_4
+ - nodejs=12.19.0=hf294227_3
+ - notebook=6.2.0=py37hf985489_0
+ - openssl=1.1.1j=hbcf498f_0
+ - pandoc=2.11.4=h35c211d_0
+ - pyrsistent=0.17.3=py37hf967b71_2
+ - pysocks=1.7.1=py37hf985489_3
+ - python=3.7.10=h7728216_100_cpython
+ - pyzmq=22.0.3=py37h8f778e5_1
+ - readline=8.0=h0678c8f_2
+ - regex=2020.11.13=py37hf967b71_1
+ - setuptools=49.6.0=py37hf985489_3
+ - sniffio=1.2.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
+ - typed-ast=1.4.2=py37hf967b71_0
+ - xz=5.2.5=haf1e3a3_1
+ - zeromq=4.3.4=h1c7c35f_0
+ - zlib=1.2.11=h7795811_1010
win-64:
- - anyio=2.1.0=py37h03978a9_0
- - argon2-cffi=20.1.0=py37hcc03f2d_2
- - 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
- - colorama=0.4.4=pyh9f0ad1d_0
- - cryptography=3.4.4=py37h65266a2_0
- - importlib-metadata=3.4.0=py37h03978a9_0
- - ipykernel=5.4.2=py37h7b7c402_0
- - ipython=7.20.0=py37heaed05f_2
- - jedi=0.18.0=py37h03978a9_2
- - jupyter_core=4.7.1=py37h03978a9_0
- - jupyter_server=1.3.0=py37h03978a9_0
- - libsodium=1.0.18=h8d14728_1
- - 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=py37hcc03f2d_3
- - mistune=0.8.4=py37hcc03f2d_1003
- - msys2-conda-epoch=20160418=1
- - mypy_extensions=0.4.3=py37h03978a9_3
- - nbconvert=6.0.7=py37h03978a9_3
- - nodejs=12.19.0=h57928b3_2
- - notebook=6.2.0=py37h03978a9_0
- - openssl=1.1.1i=h8ffe710_0
- - pandoc=2.11.4=h8ffe710_0
- - pyrsistent=0.17.3=py37hcc03f2d_2
- - pysocks=1.7.1=py37h03978a9_3
- - python=3.7.9=h7840368_0_cpython
- - pywin32=300=py37hcc03f2d_0
- - pywinpty=0.5.7=py37hc8dfbb8_1
- - pyzmq=22.0.1=py37h0d95fc2_0
- - regex=2020.11.13=py37hcc03f2d_1
- - setuptools=49.6.0=py37h03978a9_3
- - sniffio=1.2.0=py37h03978a9_1
- - sqlite=3.34.0=h8ffe710_0
- - terminado=0.9.2=py37h03978a9_0
- - tornado=6.1=py37hcc03f2d_1
- - typed-ast=1.4.2=py37hcc03f2d_0
- - vc=14.2=hb210afc_3
- - vs2015_runtime=14.28.29325=h5e1d092_3
- - win_inet_pton=1.1.0=py37h03978a9_2
- - wincertstore=0.2=py37h03978a9_1006
- - winpty=0.4.3=4
- - zeromq=4.3.3=h0e60522_3
+ - anyio=2.2.0=py37h03978a9_0
+ - argon2-cffi=20.1.0=py37hcc03f2d_2
+ - brotlipy=0.7.0=py37hcc03f2d_1001
+ - ca-certificates=2020.12.5=h5b45459_0
+ - certifi=2020.12.5=py37h03978a9_1
+ - cffi=1.14.5=py37hd8e9650_0
+ - chardet=4.0.0=py37h03978a9_1
+ - colorama=0.4.4=pyh9f0ad1d_0
+ - cryptography=3.4.4=py37h65266a2_0
+ - importlib-metadata=3.7.0=py37h03978a9_0
+ - ipykernel=5.5.0=py37heaed05f_1
+ - ipython=7.21.0=py37heaed05f_0
+ - jedi=0.18.0=py37h03978a9_2
+ - jupyter_core=4.7.1=py37h03978a9_0
+ - jupyter_server=1.4.1=py37h03978a9_0
+ - libsodium=1.0.18=h8d14728_1
+ - 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=py37hcc03f2d_3
+ - mistune=0.8.4=py37hcc03f2d_1003
+ - msys2-conda-epoch=20160418=1
+ - mypy_extensions=0.4.3=py37h03978a9_3
+ - nbconvert=6.0.7=py37h03978a9_3
+ - nodejs=12.19.0=h57928b3_3
+ - notebook=6.2.0=py37h03978a9_0
+ - openssl=1.1.1j=h8ffe710_0
+ - pandoc=2.11.4=h8ffe710_0
+ - pyrsistent=0.17.3=py37hcc03f2d_2
+ - pysocks=1.7.1=py37h03978a9_3
+ - python=3.7.10=h7840368_100_cpython
+ - pywin32=300=py37hcc03f2d_0
+ - pywinpty=0.5.7=py37hc8dfbb8_1
+ - pyzmq=22.0.3=py37hcce574b_1
+ - regex=2020.11.13=py37hcc03f2d_1
+ - setuptools=49.6.0=py37h03978a9_3
+ - sniffio=1.2.0=py37h03978a9_1
+ - sqlite=3.34.0=h8ffe710_0
+ - terminado=0.9.2=py37h03978a9_0
+ - tornado=6.1=py37hcc03f2d_1
+ - typed-ast=1.4.2=py37hcc03f2d_0
+ - vc=14.2=hb210afc_3
+ - vs2015_runtime=14.28.29325=h5e1d092_3
+ - win_inet_pton=1.1.0=py37h03978a9_2
+ - wincertstore=0.2=py37h03978a9_1006
+ - winpty=0.4.3=4
+ - zeromq=4.3.4=h0e60522_0
build:
locked: true
env_spec_hash: bcd31b2b6ceae32cda53bdd935c86f9c8d4b5a4b
platforms:
- - linux-64
- - osx-64
- - win-64
+ - linux-64
+ - osx-64
+ - win-64
packages:
all:
- - bleach=3.2.2=pyh44b312d_0
- - colorama=0.4.4=pyh9f0ad1d_0
- - conda=4.8.3=py37hc8dfbb8_1
- - idna=2.10=pyh9f0ad1d_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.7.4=pyhd8ed1ab_0
- - pyopenssl=20.0.1=pyhd8ed1ab_0
- - pyparsing=2.4.7=pyh9f0ad1d_0
- - python_abi=3.7=1_cp37m
- - readme_renderer=27.0=pyh9f0ad1d_0
- - requests-toolbelt=0.9.1=py_0
- - requests=2.25.1=pyhd3deb0d_0
- - rfc3986=1.4.0=pyh9f0ad1d_0
- - six=1.15.0=pyh9f0ad1d_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.36.2=pyhd3deb0d_0
- - zipp=3.4.0=py_0
+ - bleach=3.2.2=pyh44b312d_0
+ - colorama=0.4.4=pyh9f0ad1d_0
+ - conda=4.8.3=py37hc8dfbb8_1
+ - idna=2.10=pyh9f0ad1d_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.7.4=pyhd8ed1ab_0
+ - pyopenssl=20.0.1=pyhd8ed1ab_0
+ - pyparsing=2.4.7=pyh9f0ad1d_0
+ - python_abi=3.7=1_cp37m
+ - readme_renderer=27.0=pyh9f0ad1d_0
+ - requests-toolbelt=0.9.1=py_0
+ - requests=2.25.1=pyhd3deb0d_0
+ - rfc3986=1.4.0=pyh9f0ad1d_0
+ - six=1.15.0=pyh9f0ad1d_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.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=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=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=h6de172a_18
- - ncurses=6.2=h58526e2_4
- - openssl=1.1.1i=h7f98852_0
- - pcre=8.44=he1b5a44_0
- - 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=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_1010
+ - _libgcc_mutex=0.1=conda_forge
+ - _openmp_mutex=4.5=1_gnu
+ - 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=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=h6de172a_18
+ - ncurses=6.2=h58526e2_4
+ - openssl=1.1.1i=h7f98852_0
+ - pcre=8.44=he1b5a44_0
+ - 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=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_1010
osx-64:
- - 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.1=habf9029_0
- - 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=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_1010
+ - 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.1=habf9029_0
+ - 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=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_1010
win-64:
- - 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
+ - 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/examples/Cytoscape_Example.ipynb b/examples/Cytoscape_Example.ipynb
index 850bae4..4effddf 100644
--- a/examples/Cytoscape_Example.ipynb
+++ b/examples/Cytoscape_Example.ipynb
@@ -66,7 +66,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.8"
+ "version": "3.7.9"
}
},
"nbformat": 4,
diff --git a/examples/Cytoscape_Viewer.ipynb b/examples/Cytoscape_Viewer.ipynb
new file mode 100644
index 0000000..b8d9c5d
--- /dev/null
+++ b/examples/Cytoscape_Viewer.ipynb
@@ -0,0 +1,145 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "equivalent-publisher",
+ "metadata": {},
+ "source": [
+ "# CytoscapeViewer Example\n",
+ "\n",
+ "In this notebook we show how to simply draw a cytoscape graph."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "grateful-dependence",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import rdflib\n",
+ "\n",
+ "from ipyradiant import FileManager, PathLoader\n",
+ "from ipyradiant.visualization import CytoscapeViewer"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "protected-tomorrow",
+ "metadata": {},
+ "source": [
+ "Let's start by getting our graph loaded in."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "about-smart",
+ "metadata": {},
+ "source": [
+ "Explain why we need a subgraph (too many nodes causes issues with cytoscape)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "grand-lingerie",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "lw = FileManager(loader=PathLoader(path=\"data\"))\n",
+ "# here we hard set what we want the file to be, but ideally a user can choose a file to work with.\n",
+ "lw.loader.file_picker.value = lw.loader.file_picker.options[\"starwars.ttl\"]\n",
+ "rdf_graph = lw.graph\n",
+ "qres = lw.graph.query(\n",
+ " \"\"\"\n",
+ " PREFIX planet: \n",
+ " PREFIX human: \n",
+ " PREFIX film: \n",
+ " \n",
+ " CONSTRUCT {\n",
+ " ?s ?p ?o .\n",
+ " }\n",
+ " WHERE {\n",
+ " ?s ?p ?o .\n",
+ " \n",
+ " VALUES (?s) {\n",
+ " (human:1)\n",
+ " (human:4)\n",
+ " (human:5)\n",
+ " (film:1)\n",
+ " (film:4)\n",
+ " (planet:1)\n",
+ " (planet:2)\n",
+ " }\n",
+ " }\n",
+ " \"\"\"\n",
+ ")\n",
+ "\n",
+ "simple_graph = rdflib.graph.Graph().parse(data=qres.serialize(format=\"xml\"))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "excessive-mixer",
+ "metadata": {},
+ "source": [
+ "## Now we can initiate the `CytoscapeViewer` object, which allows us to get a nice representation of an RDF or networkx graph"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "accompanied-plymouth",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Try changing edge_labels=False for a cleaner (if less informative) visualization\n",
+ "cv = CytoscapeViewer(animate=True, node_labels=True, edge_labels=True)\n",
+ "cv.graph = simple_graph"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "infrared-renaissance",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "cv"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "hearing-coverage",
+ "metadata": {},
+ "source": [
+ "> The literal data from the RDF graph is collapsed onto the node based on the `RDF2NX`\n",
+ "> converter. For more information see [this example](RDF_to_NX.ipynb).\n",
+ "\n",
+ "> For a method to link the cytoscape graph to a JSON viewer in order to inspect node\n",
+ "> data, see [this example](JSON_Interactive_Example.ipynb)."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.7.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/examples/Datashader_Example.ipynb b/examples/Datashader_Example.ipynb
index d09a66e..4878de6 100644
--- a/examples/Datashader_Example.ipynb
+++ b/examples/Datashader_Example.ipynb
@@ -69,7 +69,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.8"
+ "version": "3.7.9"
}
},
"nbformat": 4,
diff --git a/examples/Improved_Vis.ipynb b/examples/Improved_Vis.ipynb
index e245068..f8e6c97 100644
--- a/examples/Improved_Vis.ipynb
+++ b/examples/Improved_Vis.ipynb
@@ -142,7 +142,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.8"
+ "version": "3.7.9"
}
},
"nbformat": 4,
diff --git a/examples/Test_CytoscapeViewer.ipynb b/examples/Test_CytoscapeViewer.ipynb
new file mode 100644
index 0000000..548c6dc
--- /dev/null
+++ b/examples/Test_CytoscapeViewer.ipynb
@@ -0,0 +1,129 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# A Basic Test for the Cytoscape Viewer"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import json\n",
+ "import os\n",
+ "import time\n",
+ "from pathlib import Path\n",
+ "\n",
+ "import importnb\n",
+ "from rdflib import Graph as RDFGraph\n",
+ "from rdflib import Literal\n",
+ "from rdflib.namespace import RDF, RDFS, Namespace\n",
+ "from requests_cache import CachedSession\n",
+ "\n",
+ "from ipyradiant.visualization import CytoscapeViewer"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "This notebook is used as part of the `ipyradiant` test suite, where `IPYRADIANT_TESTING`\n",
+ "will be set, which will trigger the automted section below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# test graph\n",
+ "EXPECTED_LEN_RDF = 0\n",
+ "EXPECTED_LEN_NX_NODES = 0\n",
+ "EXPECTED_LEN_NX_EDGES = 0\n",
+ "\n",
+ "EX = Namespace(\"https://www.example.com/\")\n",
+ "graph = RDFGraph()\n",
+ "graph.namespace_manager.bind(\"ex\", EX)\n",
+ "\n",
+ "s1 = EX.subject_1\n",
+ "graph.add((s1, RDF.type, EX.Thing))\n",
+ "graph.add((s1, RDFS.label, Literal(\"Thing 1\")))\n",
+ "EXPECTED_LEN_RDF += 2\n",
+ "EXPECTED_LEN_NX_NODES += 1\n",
+ "\n",
+ "s2 = EX.subject_2\n",
+ "graph.add((s2, RDF.type, EX.Thing))\n",
+ "graph.add((s2, RDFS.label, Literal(\"Thing 2\")))\n",
+ "EXPECTED_LEN_RDF += 2\n",
+ "EXPECTED_LEN_NX_NODES += 1\n",
+ "\n",
+ "graph.add((s1, EX.relatedTo, s2))\n",
+ "EXPECTED_LEN_RDF += 1\n",
+ "EXPECTED_LEN_NX_EDGES += 1"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def timestamp(msg):\n",
+ " print(f\"[{time.time()}]\", msg)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "try:\n",
+ " timestamp(\"initiating...\")\n",
+ " cv = CytoscapeViewer()\n",
+ " timestamp(\"initiated...\")\n",
+ " assert cv.graph is None\n",
+ " timestamp(\"setting rdf graph...\")\n",
+ " assert len(graph) == EXPECTED_LEN_RDF\n",
+ " cv.graph = graph\n",
+ " assert len(cv.graph), \"Graph failed to populate.\"\n",
+ " timestamp(\"graph set successfully\")\n",
+ " assert len(cv.cytoscape_widget.graph.nodes) > 0, \"CytoscapeWidget failed to update.\"\n",
+ " assert len(cv.cytoscape_widget.graph.nodes) == EXPECTED_LEN_NX_NODES\n",
+ " assert len(cv.cytoscape_widget.graph.edges) == EXPECTED_LEN_NX_EDGES\n",
+ " timestamp(\"graph converted successfully...\")\n",
+ " timestamp(\"OK!\")\n",
+ "except Exception as err:\n",
+ " timestamp(\"ERROR\")\n",
+ " timestamp(err)\n",
+ " raise Exception(f\"{p} failed\") from err"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3",
+ "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.7.9"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 4
+}
diff --git a/examples/Test_GraphExplorer.ipynb b/examples/Test_GraphExplorer.ipynb
index 690ebb6..63e9566 100644
--- a/examples/Test_GraphExplorer.ipynb
+++ b/examples/Test_GraphExplorer.ipynb
@@ -195,7 +195,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.8"
+ "version": "3.7.9"
}
},
"nbformat": 4,
diff --git a/index.ipynb b/index.ipynb
index f0df007..e871dba 100644
--- a/index.ipynb
+++ b/index.ipynb
@@ -21,6 +21,7 @@
"\n",
"### 3. Graph Visualization Widgets\n",
"- Cytoscape for Small Interactive Graphs\n",
+ "- Cytoscape with RDF to LPG converter for Visualizing Small Graphs\n",
"- Datashader for Large Graphs\n",
"- Graph Explorer (`ipycytoscape`).\n",
"\n",
@@ -32,7 +33,7 @@
"- Remote Query Examples\n",
"- Federated Query Examples\n",
"\n",
- "### 6. RDF to Networkx\n",
+ "### 6. RDF to `networkx`\n",
"- Collapsing RDF to a Latent Property Graph (networkx)\n",
"- URI Converters for RDF2NX process\n",
"\n",
@@ -70,7 +71,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.7.8"
+ "version": "3.7.9"
}
},
"nbformat": 4,
diff --git a/src/ipyradiant/rdf2nx/converter.py b/src/ipyradiant/rdf2nx/converter.py
index fe0709e..a3457d1 100644
--- a/src/ipyradiant/rdf2nx/converter.py
+++ b/src/ipyradiant/rdf2nx/converter.py
@@ -2,6 +2,7 @@
# Distributed under the terms of the Modified BSD License.
import logging
from typing import Callable, Dict, List, Union
+from warnings import warn
from networkx import MultiDiGraph
from pandas import DataFrame
@@ -221,9 +222,9 @@ def convert(
if namespaces is None:
namespaces = dict(rdf_graph.namespaces())
cls.initNs = dict(namespaces)
- assert (
- "base" in cls.initNs
- ), "For conversion, namespaces must include a base namespace."
+ if "base" not in cls.initNs:
+ warn("No base namespace specified. Defaulting to example namespace")
+ cls.initNs["base"] = URIRef("https://www.example.com/RDF2NX/")
nx_graph = MultiDiGraph()
diff --git a/src/ipyradiant/rdf2nx/literal_converter.py b/src/ipyradiant/rdf2nx/literal_converter.py
index 8e09a2d..d8d02bf 100644
--- a/src/ipyradiant/rdf2nx/literal_converter.py
+++ b/src/ipyradiant/rdf2nx/literal_converter.py
@@ -52,4 +52,6 @@ def cast_literal(value: Literal, strict: bool = False) -> Any:
)
return str(value)
else:
+ if value.value is None:
+ return None
return XSD2PY[value_datatype](value)
diff --git a/src/ipyradiant/rdf2nx/nodes.py b/src/ipyradiant/rdf2nx/nodes.py
index 6d74735..3553ec7 100644
--- a/src/ipyradiant/rdf2nx/nodes.py
+++ b/src/ipyradiant/rdf2nx/nodes.py
@@ -70,3 +70,31 @@ class NodeProperties(SPARQLQueryFramer):
?iri ?predicate ?value.
}
"""
+
+
+class NodeAnnotationProperties(SPARQLQueryFramer):
+ """An example of how to return properties for a LPG node.
+ - ?iri: bound to a specific node IRI, to get the properties for that node.
+ - ?predicate: IRI for the property name (e.g. ex:hasThing) and is converted into a
+ shorter ID by means of a configured IRI->ID converter.
+ - ?value: a literal that may be converted using its lexical value.
+
+ TODO experimental, taken from https://www.w3.org/TR/rdf-schema/#ch_properties
+ """
+
+ sparql = """
+ SELECT DISTINCT ?iri ?predicate ?value
+ {
+ ?iri ?predicate ?value.
+
+ VALUES (?predicate) {
+ (rdfs:range)
+ (rdfs:domain)
+ (rdf:type)
+ (rdfs:subClassOf)
+ (rdfs:subPropertyOf) # TODO remove this one?
+ (rdfs:label)
+ (rdfs:comment)
+ }
+ }
+ """
diff --git a/src/ipyradiant/visualization/__init__.py b/src/ipyradiant/visualization/__init__.py
index 2ce7367..c357745 100644
--- a/src/ipyradiant/visualization/__init__.py
+++ b/src/ipyradiant/visualization/__init__.py
@@ -11,9 +11,11 @@
"NXBase",
"InteractiveViewer",
"GetOutgoingPredicateObjects",
+ "CytoscapeViewer",
]
from .base import NXBase, VisualizerBase
from .cytoscape import CytoscapeVisualizer
from .datashader_vis import DatashaderVisualizer
from .explore import GetOutgoingPredicateObjects, InteractiveViewer
+from .improved_cytoscape import CytoscapeViewer
from .tools import LayoutSelector
diff --git a/src/ipyradiant/visualization/cytoscape/__init__.py b/src/ipyradiant/visualization/cytoscape/__init__.py
new file mode 100644
index 0000000..62db742
--- /dev/null
+++ b/src/ipyradiant/visualization/cytoscape/__init__.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2021 ipyradiant contributors.
+# Distributed under the terms of the Modified BSD License.
+
+__all__ = ["CytoscapeVisualizer"]
+
+from .app import CytoscapeVisualizer
diff --git a/src/ipyradiant/visualization/cytoscape.py b/src/ipyradiant/visualization/cytoscape/app.py
similarity index 99%
rename from src/ipyradiant/visualization/cytoscape.py
rename to src/ipyradiant/visualization/cytoscape/app.py
index 7bbb1c3..704fd7a 100644
--- a/src/ipyradiant/visualization/cytoscape.py
+++ b/src/ipyradiant/visualization/cytoscape/app.py
@@ -9,7 +9,7 @@
from rdflib import Graph, Literal, URIRef
from rdflib.namespace import RDF
-from .base import VisualizerBase
+from ..base import VisualizerBase
class CytoscapeVisualizer(VisualizerBase):
diff --git a/src/ipyradiant/visualization/cytoscape/style.py b/src/ipyradiant/visualization/cytoscape/style.py
new file mode 100644
index 0000000..6e6e232
--- /dev/null
+++ b/src/ipyradiant/visualization/cytoscape/style.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2021 ipyradiant contributors.
+# Distributed under the terms of the Modified BSD License.
+
+NODE = {
+ "selector": "node",
+ "style": {
+ "color": "black",
+ "background-color": "CadetBlue",
+ },
+}
+
+LABELLED_NODE = {
+ "selector": "node",
+ "style": {
+ "color": "black",
+ "background-color": "CadetBlue",
+ "label": "data(_label)",
+ },
+}
+
+EDGE = {
+ "selector": "edge",
+ "style": {
+ "line-color": "grey",
+ "line-opacity": "0.5",
+ },
+}
+
+LABELLED_EDGE = {
+ "selector": "edge",
+ "style": {
+ "font-size": "12",
+ "font-style": "italic",
+ "line-color": "grey",
+ "line-opacity": "0.5",
+ "label": "data(_label)",
+ },
+}
+
+
+DIRECTED_EDGE = {
+ "selector": "edge.directed",
+ "style": {"curve-style": "bezier", "target-arrow-shape": "triangle"},
+}
+
+MULTIPLE_EDGES = {
+ "selector": "edge.multiple_edges",
+ "style": {"curve-style": "bezier"},
+}
+
+DIRECTED_GRAPH = [
+ NODE,
+ EDGE,
+ DIRECTED_EDGE,
+ MULTIPLE_EDGES,
+]
+
+LABELLED_DIRECTED_GRAPH = [
+ LABELLED_NODE,
+ LABELLED_EDGE,
+ DIRECTED_EDGE,
+ MULTIPLE_EDGES,
+]
diff --git a/src/ipyradiant/visualization/improved_cytoscape.py b/src/ipyradiant/visualization/improved_cytoscape.py
new file mode 100644
index 0000000..d5df452
--- /dev/null
+++ b/src/ipyradiant/visualization/improved_cytoscape.py
@@ -0,0 +1,190 @@
+# Copyright (c) 2021 ipyradiant contributors.
+# Distributed under the terms of the Modified BSD License.
+import ipycytoscape as cyto
+import ipywidgets as W
+import networkx as nx
+import rdflib
+import traitlets as T
+from ipycytoscape.cytoscape import Graph as CytoscapeGraph
+
+from ipyradiant.rdf2nx import RDF2NX
+from ipyradiant.visualization.cytoscape import style
+
+MAX_NODES = 300
+MAX_EDGES = MAX_NODES * 3
+
+
+class CytoscapeViewer(W.VBox):
+ """A simple Cytoscape graph visualizer that can render RDF and networkx graphs.
+
+ :param animate: flag for turning cytoscape animations on/off
+ :param node_labels: flag for turning node labels on/off
+ :param edge_labels: flag for turning edge labels on/off
+ :param layouts: list of optional layouts for the ipycytoscape.CytoscapeWidget
+ :param layout_selector: ipywidgets Dropdown for storing cytoscape layouts
+ :param cytoscape_widget: ipycytoscape.CytoscapeWidget for rendering the graph
+ :param graph: a networkx or rdflib Graph to render
+ :param cyto_layout: the selected cytoscape graph layout
+ :param cyto_style: the style used when rendering the cytoscape graph
+ :param _render_large_graphs: flag to prevent long expensive layout computations for large graphs
+ :param _rdf_label: attribute to use when discovering labels for RDF nodes (post-LPG conversion)
+ :param _nx_label: attribute to use when discovering labels for networkx nodes
+ :param _rdf_converter: converter class that transforms the input RDF graph to networkx
+ """
+
+ animate = T.Bool(default_value=True)
+ node_labels = T.Bool(default_value=True)
+ edge_labels = T.Bool(default_value=True)
+ layouts = T.List()
+ layout_selector = T.Instance(W.Dropdown)
+ cytoscape_widget = T.Instance(cyto.CytoscapeWidget)
+ graph = T.Union(
+ (
+ T.Instance(rdflib.Graph),
+ T.Instance(nx.Graph),
+ ),
+ allow_none=True,
+ default_value=None,
+ )
+ cyto_layout = T.Unicode(default_value="random")
+ cyto_style = T.List()
+ _render_large_graphs = False
+ _rdf_label = "rdfs:label"
+ _nx_label = "label"
+ _rdf_converter: RDF2NX = RDF2NX
+
+ def update_style(self):
+ """Update style based on class attributes."""
+ style_list = [style.DIRECTED_EDGE, style.MULTIPLE_EDGES]
+ if self.node_labels and self.edge_labels:
+ style_list = style.LABELLED_DIRECTED_GRAPH
+ elif not self.node_labels and not self.edge_labels:
+ style_list = style.DIRECTED_GRAPH
+ else:
+ if self.node_labels:
+ style_list.append(style.LABELLED_NODE)
+ else:
+ style_list.append(style.NODE)
+ if self.edge_labels:
+ style_list.append(style.LABELLED_EDGE)
+ else:
+ style_list.append(style.EDGE)
+
+ self.cyto_style = style_list
+
+ def update_cytoscape_frontend(self):
+ """A temporary workaround to trigger a frontend refresh"""
+
+ self.cytoscape_widget.graph.add_node(cyto.Node(data={"id": "random node"}))
+ self.cytoscape_widget.graph.remove_node_by_id("random node")
+
+ @T.default("cyto_style")
+ def _make_cyto_style(self):
+ self.update_style()
+ return self.cyto_style
+
+ @T.validate("graph")
+ def _valid_graph(self, proposal):
+ """Validate graph by throwing error when # nodes/edges is at the limits of ipycytoscape
+
+ TODO is there a better way to determine the limits than arbitrary numbers?
+ """
+
+ graph = proposal["value"]
+ if (
+ isinstance(graph, nx.Graph)
+ and not self._render_large_graphs
+ and (len(graph.nodes) > MAX_NODES or len(graph.edges) > MAX_EDGES)
+ ):
+ raise T.TraitError(
+ f"unable to render networkx graphs with more than {MAX_NODES} nodes or {MAX_EDGES} edges."
+ )
+ elif (
+ isinstance(graph, rdflib.Graph)
+ and not self._render_large_graphs
+ and (len(graph) > MAX_EDGES + MAX_NODES)
+ ):
+ raise T.TraitError(
+ f"unable to render RDF graphs with more than {MAX_EDGES+MAX_NODES} triples."
+ )
+ return graph
+
+ @T.observe("graph")
+ def _update_graph(self, change):
+ # Clear graph so that data isn't duplicated
+ self.cytoscape_widget.graph = CytoscapeGraph()
+ if isinstance(self.graph, nx.Graph):
+ self.cytoscape_widget.graph.add_graph_from_networkx(self.graph)
+ # TODO def add_label_from_nx
+ for node in self.cytoscape_widget.graph.nodes:
+ node.data["_label"] = node.data.get(self._nx_label, None)
+ elif isinstance(self.graph, rdflib.Graph):
+ # Note: rdflib_to_networkx_multidigraph does not store the predicate AT ALL,
+ # so it is basically unrecoverable (e.g. for labelling); using _rdf_converter
+ nx_graph = self._rdf_converter.convert(self.graph)
+ self.cytoscape_widget.graph.add_graph_from_networkx(nx_graph)
+ for node in self.cytoscape_widget.graph.nodes:
+ node.data["_label"] = node.data.get(
+ self._rdf_label, node.data.get("id", None)
+ )
+
+ @T.default("cytoscape_widget")
+ def _make_cytoscape_widget(self):
+ widget = cyto.CytoscapeWidget()
+ widget.set_layout(
+ animate=self.animate,
+ randomize=True,
+ # Fast animation time for initial graph
+ maxSimulationTime=1000,
+ )
+ widget.set_style(self.cyto_style)
+ return widget
+
+ @T.observe("node_labels", "edge_labels")
+ def _update_labels(self, change):
+ self.update_style()
+
+ @T.default("layouts")
+ def _make_layouts(self):
+ # TODO increase spacing on the layout?
+ # https://stackoverflow.com/questions/54015729
+ return ["circle", "cola", "concentric", "cose", "dagre", "grid", "random"]
+
+ @T.default("layout_selector")
+ def _make_layout_selector(self):
+ widget = W.Dropdown(description="Layout:", options=self.layouts)
+ T.link((self, "cyto_layout"), (widget, "value"))
+ return widget
+
+ @T.observe("layouts")
+ def _update_layout_selector(self, change):
+ self.layout_selector = self._make_layout_selector()
+
+ @T.observe("cyto_layout")
+ def _update_layout(self, change):
+ # TODO move to .cytoscape.layout
+ # note: animate=False goes through the full simulation to compute layout, which is SLOW
+ self.cytoscape_widget.set_layout(
+ name=self.cyto_layout,
+ animate=self.animate,
+ randomize=True,
+ maxSimulationTime=2000,
+ )
+
+ @T.observe("cyto_style")
+ def _update_style(self, change):
+ self.cytoscape_widget.set_style(self.cyto_style)
+
+ @T.validate("children")
+ def validate_children(self, proposal):
+ """
+ Validate method for default children.
+ This is necessary because @trt.default does not work on children.
+ """
+ children = proposal.value
+ if not children:
+ children = (
+ self.layout_selector,
+ self.cytoscape_widget,
+ )
+ return children