diff --git a/t_sne_roots/anaconda-project-lock.yml b/t_sne_roots/anaconda-project-lock.yml
new file mode 100644
index 000000000..044487289
--- /dev/null
+++ b/t_sne_roots/anaconda-project-lock.yml
@@ -0,0 +1,782 @@
+# This is an Anaconda project lock file.
+# The lock file locks down exact versions of all your dependencies.
+#
+# In most cases, this file is automatically maintained by the `anaconda-project` command or GUI tools.
+# It's best to keep this file in revision control (such as git or svn).
+# The file is in YAML format, please see http://www.yaml.org/start.html for more.
+#
+
+#
+# Set to false to ignore locked versions.
+#
+locking_enabled: true
+
+#
+# A key goes in here for each env spec.
+#
+env_specs:
+ default:
+ locked: true
+ env_spec_hash: e0ebb18beaec5067f86a9ddb056b9f859b9bc408
+ platforms:
+ - linux-64
+ - osx-64
+ - osx-arm64
+ - win-64
+ packages:
+ all:
+ - argon2-cffi=21.3.0=pyhd3eb1b0_0
+ - asttokens=2.0.5=pyhd3eb1b0_0
+ - backcall=0.2.0=pyhd3eb1b0_0
+ - bleach=4.1.0=pyhd3eb1b0_0
+ - bokeh=3.3.2=pyhd8ed1ab_0
+ - charset-normalizer=2.0.4=pyhd3eb1b0_0
+ - cycler=0.11.0=pyhd3eb1b0_0
+ - decorator=5.1.1=pyhd3eb1b0_0
+ - defusedxml=0.7.1=pyhd3eb1b0_0
+ - executing=0.8.3=pyhd3eb1b0_0
+ - fonttools=4.25.0=pyhd3eb1b0_0
+ - importlib_metadata=6.0.0=hd3eb1b0_0
+ - json5=0.9.6=pyhd3eb1b0_0
+ - jupyterlab_pygments=0.1.2=py_0
+ - munkres=1.1.4=py_0
+ - pandocfilters=1.5.0=pyhd3eb1b0_0
+ - parso=0.8.3=pyhd3eb1b0_0
+ - pickleshare=0.7.5=pyhd3eb1b0_1003
+ - pure_eval=0.2.2=pyhd3eb1b0_0
+ - pyarrow-hotfix=0.6=pyhd8ed1ab_0
+ - pycparser=2.21=pyhd3eb1b0_0
+ - python-dateutil=2.8.2=pyhd3eb1b0_0
+ - python-tzdata=2023.3=pyhd3eb1b0_0
+ - six=1.16.0=pyhd3eb1b0_1
+ - stack_data=0.2.0=pyhd3eb1b0_0
+ - tzdata=2023c=h04d1e81_0
+ - wcwidth=0.2.5=pyhd3eb1b0_0
+ unix:
+ - blas=1.0=openblas
+ - pexpect=4.8.0=pyhd3eb1b0_3
+ - ptyprocess=0.7.0=pyhd3eb1b0_2
+ linux-64:
+ - _libgcc_mutex=0.1=conda_forge
+ - _openmp_mutex=4.5=2_gnu
+ - abseil-cpp=20211102.0=hd4dd3e8_0
+ - anyio=3.5.0=py39h06a4308_0
+ - argon2-cffi-bindings=21.2.0=py39h7f8727e_0
+ - arrow-cpp=11.0.0=hda39474_2
+ - async-lru=2.0.4=py39h06a4308_0
+ - attrs=23.1.0=py39h06a4308_0
+ - aws-c-common=0.4.57=he6710b0_1
+ - aws-c-event-stream=0.1.6=h2531618_5
+ - aws-checksums=0.1.9=he6710b0_0
+ - aws-sdk-cpp=1.8.185=hce553d0_0
+ - babel=2.11.0=py39h06a4308_0
+ - beautifulsoup4=4.12.2=py39h06a4308_0
+ - boost-cpp=1.82.0=hdb19cb5_2
+ - bottleneck=1.3.5=py39h7deecbd_0
+ - brotli-bin=1.0.9=h5eee18b_7
+ - brotli-python=1.0.9=py39h6a678d5_7
+ - brotli=1.0.9=h5eee18b_7
+ - bzip2=1.0.8=h7b6447c_0
+ - c-ares=1.19.1=h5eee18b_0
+ - ca-certificates=2023.08.22=h06a4308_0
+ - certifi=2023.11.17=py39h06a4308_0
+ - cffi=1.15.1=py39h74dc2b5_0
+ - click=8.1.7=py39h06a4308_0
+ - cloudpickle=2.2.1=py39h06a4308_0
+ - colorcet=3.0.1=py39h06a4308_0
+ - comm=0.1.2=py39h06a4308_0
+ - contourpy=1.2.0=py39hdb19cb5_0
+ - cryptography=41.0.3=py39h130f0dd_0
+ - dask-core=2023.11.0=py39h06a4308_0
+ - datashader=0.16.0=py39h06a4308_0
+ - debugpy=1.6.7=py39h6a678d5_0
+ - exceptiongroup=1.0.4=py39h06a4308_0
+ - freetype=2.12.1=h4a9f257_0
+ - fsspec=2023.10.0=py39h06a4308_0
+ - gflags=2.2.2=he6710b0_0
+ - giflib=5.2.1=h5eee18b_3
+ - glog=0.5.0=h2531618_0
+ - grpc-cpp=1.48.2=h5bf31a4_0
+ - holoviews=1.18.1=py39h06a4308_0
+ - icu=73.1=h6a678d5_0
+ - idna=3.4=py39h06a4308_0
+ - importlib-metadata=6.0.0=py39h06a4308_0
+ - importlib_resources=6.1.0=py39h06a4308_0
+ - ipykernel=6.25.0=py39h2f386ee_0
+ - ipython=8.15.0=py39h06a4308_0
+ - jedi=0.18.1=py39h06a4308_1
+ - jinja2=3.1.2=py39h06a4308_0
+ - jpeg=9e=h5eee18b_1
+ - jsonschema-specifications=2023.7.1=py39h06a4308_0
+ - jsonschema=4.19.2=py39h06a4308_0
+ - jupyter-lsp=2.2.0=py39h06a4308_0
+ - jupyter_client=8.6.0=py39h06a4308_0
+ - jupyter_core=5.5.0=py39h06a4308_0
+ - jupyter_events=0.8.0=py39h06a4308_0
+ - jupyter_server=2.10.0=py39h06a4308_0
+ - jupyter_server_terminals=0.4.4=py39h06a4308_1
+ - jupyterlab=4.0.8=py39h06a4308_0
+ - jupyterlab_server=2.25.1=py39h06a4308_0
+ - kiwisolver=1.4.4=py39h6a678d5_0
+ - krb5=1.20.1=h568e23c_1
+ - lcms2=2.12=h3be6417_0
+ - ld_impl_linux-64=2.38=h1181459_1
+ - lerc=3.0=h295c915_0
+ - libboost=1.82.0=h109eef0_2
+ - libbrotlicommon=1.0.9=h5eee18b_7
+ - libbrotlidec=1.0.9=h5eee18b_7
+ - libbrotlienc=1.0.9=h5eee18b_7
+ - libcurl=8.2.1=h91b91d3_0
+ - libdeflate=1.17=h5eee18b_1
+ - libedit=3.1.20221030=h5eee18b_0
+ - libev=4.33=h7f8727e_1
+ - libevent=2.1.12=h8f2d780_0
+ - libffi=3.3=he6710b0_2
+ - libgcc-ng=13.2.0=h807b86a_3
+ - libgfortran-ng=13.2.0=h69a702a_3
+ - libgfortran5=13.2.0=ha4646dd_3
+ - libgomp=13.2.0=h807b86a_3
+ - libllvm14=14.0.6=hef93074_0
+ - libnghttp2=1.52.0=ha637b67_1
+ - libopenblas=0.3.21=h043d6bf_0
+ - libpng=1.6.39=h5eee18b_0
+ - libprotobuf=3.20.3=he621ea3_0
+ - libsodium=1.0.18=h7b6447c_0
+ - libssh2=1.10.0=h37d81fd_2
+ - libstdcxx-ng=13.2.0=h7e041cc_3
+ - libthrift=0.15.0=h0d84882_2
+ - libtiff=4.5.1=h6a678d5_0
+ - libwebp-base=1.3.2=h5eee18b_0
+ - libwebp=1.3.2=h11a3e52_0
+ - libzlib=1.2.13=hd590300_5
+ - linkify-it-py=2.0.0=py39h06a4308_0
+ - llvmlite=0.41.1=py39h174d805_0
+ - locket=1.0.0=py39h06a4308_0
+ - lz4-c=1.9.4=h6a678d5_0
+ - markdown-it-py=2.2.0=py39h06a4308_1
+ - markdown=3.4.1=py39h06a4308_0
+ - markupsafe=2.1.1=py39h7f8727e_0
+ - matplotlib-base=3.8.0=py39h1128e8f_0
+ - matplotlib-inline=0.1.6=py39h06a4308_0
+ - mdit-py-plugins=0.3.0=py39h06a4308_0
+ - mdurl=0.1.0=py39h06a4308_0
+ - mistune=2.0.4=py39h06a4308_0
+ - multipledispatch=0.6.0=py39h06a4308_0
+ - nbclient=0.8.0=py39h06a4308_0
+ - nbconvert=7.10.0=py39h06a4308_0
+ - nbformat=5.9.2=py39h06a4308_0
+ - ncurses=6.4=h6a678d5_0
+ - nest-asyncio=1.5.6=py39h06a4308_0
+ - notebook-shim=0.2.3=py39h06a4308_0
+ - notebook=7.0.6=py39h06a4308_0
+ - numba=0.58.1=py39h615d6bd_0
+ - numexpr=2.8.7=py39h286c3b5_0
+ - numpy-base=1.26.2=py39h8a23956_0
+ - numpy=1.26.2=py39heeff2f4_0
+ - openjpeg=2.4.0=h3ad879b_0
+ - openssl=1.1.1w=h7f8727e_0
+ - orc=1.7.4=hb3bc3d3_1
+ - overrides=7.4.0=py39h06a4308_0
+ - packaging=23.1=py39h06a4308_0
+ - pandas=2.1.1=py39h1128e8f_0
+ - panel=1.3.1=py39h06a4308_0
+ - param=2.0.1=py39h06a4308_0
+ - partd=1.4.1=py39h06a4308_0
+ - pillow=10.0.1=py39ha6cbd5a_0
+ - pip=23.3.1=py39h06a4308_0
+ - platformdirs=3.10.0=py39h06a4308_0
+ - prometheus_client=0.14.1=py39h06a4308_0
+ - prompt-toolkit=3.0.36=py39h06a4308_0
+ - psutil=5.9.0=py39h5eee18b_0
+ - pyarrow=11.0.0=py39h468efa6_1
+ - pyct=0.5.0=py39h06a4308_0
+ - pygments=2.15.1=py39h06a4308_1
+ - pyopenssl=23.2.0=py39h06a4308_0
+ - pyparsing=3.0.9=py39h06a4308_0
+ - pysocks=1.7.1=py39h06a4308_0
+ - python-fastjsonschema=2.16.2=py39h06a4308_0
+ - python-json-logger=2.0.7=py39h06a4308_0
+ - python=3.9.0=hdb3f193_2
+ - python_abi=3.9=2_cp39
+ - pytz=2023.3.post1=py39h06a4308_0
+ - pyviz_comms=3.0.0=py39h06a4308_0
+ - pyyaml=6.0.1=py39h5eee18b_0
+ - pyzmq=25.1.0=py39h6a678d5_0
+ - re2=2022.04.01=h295c915_0
+ - readline=8.2=h5eee18b_0
+ - referencing=0.30.2=py39h06a4308_0
+ - requests=2.31.0=py39h06a4308_0
+ - rfc3339-validator=0.1.4=py39h06a4308_0
+ - rfc3986-validator=0.1.1=py39h06a4308_0
+ - rpds-py=0.10.6=py39hb02cf49_0
+ - scipy=1.11.4=py39heeff2f4_0
+ - send2trash=1.8.2=py39h06a4308_0
+ - setuptools=68.0.0=py39h06a4308_0
+ - snappy=1.1.9=h295c915_0
+ - sniffio=1.2.0=py39h06a4308_1
+ - soupsieve=2.5=py39h06a4308_0
+ - sqlite=3.41.2=h5eee18b_0
+ - terminado=0.17.1=py39h06a4308_0
+ - tinycss2=1.2.1=py39h06a4308_0
+ - tk=8.6.12=h1ccaba5_0
+ - tomli=2.0.1=py39h06a4308_0
+ - toolz=0.12.0=py39h06a4308_0
+ - tornado=6.3.3=py39h5eee18b_0
+ - tqdm=4.65.0=py39hb070fc8_0
+ - traitlets=5.7.1=py39h06a4308_0
+ - typing-extensions=4.7.1=py39h06a4308_0
+ - typing_extensions=4.7.1=py39h06a4308_0
+ - uc-micro-py=1.0.1=py39h06a4308_0
+ - urllib3=1.26.18=py39h06a4308_0
+ - utf8proc=2.6.1=h27cfd23_0
+ - webencodings=0.5.1=py39h06a4308_1
+ - websocket-client=0.58.0=py39h06a4308_4
+ - wheel=0.41.2=py39h06a4308_0
+ - xarray=2023.6.0=py39h06a4308_0
+ - xyzservices=2022.9.0=py39h06a4308_1
+ - xz=5.4.5=h5eee18b_0
+ - yaml=0.2.5=h7b6447c_0
+ - zeromq=4.3.4=h2531618_0
+ - zipp=3.11.0=py39h06a4308_0
+ - zlib=1.2.13=hd590300_5
+ - zstd=1.5.5=hc292b87_0
+ osx-64:
+ - abseil-cpp=20211102.0=he9d5cce_0
+ - anyio=3.5.0=py39hecd8cb5_0
+ - appnope=0.1.2=py39hecd8cb5_1001
+ - argon2-cffi-bindings=21.2.0=py39hca72f7f_0
+ - arrow-cpp=11.0.0=h9980dd5_2
+ - async-lru=2.0.4=py39hecd8cb5_0
+ - attrs=23.1.0=py39hecd8cb5_0
+ - aws-c-common=0.4.57=hb1e8313_1
+ - aws-c-event-stream=0.1.6=h23ab428_5
+ - aws-checksums=0.1.9=hb1e8313_0
+ - aws-sdk-cpp=1.8.185=he271ece_0
+ - babel=2.11.0=py39hecd8cb5_0
+ - beautifulsoup4=4.12.2=py39hecd8cb5_0
+ - boost-cpp=1.82.0=ha357a0b_2
+ - bottleneck=1.3.5=py39h67323c0_0
+ - brotli-bin=1.0.9=hca72f7f_7
+ - brotli-python=1.0.9=py39he9d5cce_7
+ - brotli=1.0.9=hca72f7f_7
+ - bzip2=1.0.8=h1de35cc_0
+ - c-ares=1.19.1=h6c40b1e_0
+ - ca-certificates=2023.08.22=hecd8cb5_0
+ - certifi=2023.11.17=py39hecd8cb5_0
+ - cffi=1.15.1=py39hc55c11b_0
+ - click=8.1.7=py39hecd8cb5_0
+ - cloudpickle=2.2.1=py39hecd8cb5_0
+ - colorcet=3.0.1=py39hecd8cb5_0
+ - comm=0.1.2=py39hecd8cb5_0
+ - contourpy=1.2.0=py39ha357a0b_0
+ - cryptography=41.0.3=py39ha2381d6_0
+ - dask-core=2023.11.0=py39hecd8cb5_0
+ - datashader=0.16.0=py39hecd8cb5_0
+ - debugpy=1.6.7=py39hcec6c5f_0
+ - exceptiongroup=1.0.4=py39hecd8cb5_0
+ - freetype=2.12.1=hd8bbffd_0
+ - fsspec=2023.10.0=py39hecd8cb5_0
+ - gflags=2.2.2=h0a44026_0
+ - giflib=5.2.1=h6c40b1e_3
+ - glog=0.5.0=h23ab428_0
+ - grpc-cpp=1.48.2=h3afe56f_0
+ - holoviews=1.18.1=py39hecd8cb5_0
+ - icu=73.1=hcec6c5f_0
+ - idna=3.4=py39hecd8cb5_0
+ - importlib-metadata=6.0.0=py39hecd8cb5_0
+ - importlib_resources=6.1.0=py39hecd8cb5_0
+ - ipykernel=6.25.0=py39h20db666_0
+ - ipython=8.15.0=py39hecd8cb5_0
+ - jedi=0.18.1=py39hecd8cb5_1
+ - jinja2=3.1.2=py39hecd8cb5_0
+ - jpeg=9e=h6c40b1e_1
+ - jsonschema-specifications=2023.7.1=py39hecd8cb5_0
+ - jsonschema=4.19.2=py39hecd8cb5_0
+ - jupyter-lsp=2.2.0=py39hecd8cb5_0
+ - jupyter_client=8.6.0=py39hecd8cb5_0
+ - jupyter_core=5.5.0=py39hecd8cb5_0
+ - jupyter_events=0.8.0=py39hecd8cb5_0
+ - jupyter_server=2.10.0=py39hecd8cb5_0
+ - jupyter_server_terminals=0.4.4=py39hecd8cb5_1
+ - jupyterlab=4.0.8=py39hecd8cb5_0
+ - jupyterlab_server=2.25.1=py39hecd8cb5_0
+ - kiwisolver=1.4.4=py39hcec6c5f_0
+ - krb5=1.20.1=hdba6334_1
+ - lcms2=2.12=hf1fd2bf_0
+ - lerc=3.0=he9d5cce_0
+ - libboost=1.82.0=hf53b9f2_2
+ - libbrotlicommon=1.0.9=hca72f7f_7
+ - libbrotlidec=1.0.9=hca72f7f_7
+ - libbrotlienc=1.0.9=hca72f7f_7
+ - libcurl=8.2.1=ha585b31_0
+ - libcxx=14.0.6=h9765a3e_0
+ - libdeflate=1.17=hb664fd8_1
+ - libedit=3.1.20221030=h6c40b1e_0
+ - libev=4.33=h9ed2024_1
+ - libevent=2.1.12=h0a4fc7d_0
+ - libffi=3.3=hb1e8313_2
+ - libgfortran5=11.3.0=h9dfd629_28
+ - libgfortran=5.0.0=11_3_0_hecd8cb5_28
+ - libiconv=1.16=hca72f7f_2
+ - libllvm14=14.0.6=he552d86_0
+ - libnghttp2=1.52.0=h1c88b7d_1
+ - libopenblas=0.3.21=h54e7dc3_0
+ - libpng=1.6.39=h6c40b1e_0
+ - libprotobuf=3.20.3=hfff2838_0
+ - libsodium=1.0.18=h1de35cc_0
+ - libssh2=1.10.0=hdb2fb19_2
+ - libthrift=0.15.0=h48f73ad_2
+ - libtiff=4.5.1=hcec6c5f_0
+ - libwebp-base=1.3.2=h6c40b1e_0
+ - libwebp=1.3.2=hf6ce154_0
+ - linkify-it-py=2.0.0=py39hecd8cb5_0
+ - llvm-openmp=14.0.6=h0dcd299_0
+ - llvmlite=0.41.0=py39hfff2838_0
+ - locket=1.0.0=py39hecd8cb5_0
+ - lz4-c=1.9.4=hcec6c5f_0
+ - markdown-it-py=2.2.0=py39hecd8cb5_1
+ - markdown=3.4.1=py39hecd8cb5_0
+ - markupsafe=2.1.1=py39hca72f7f_0
+ - matplotlib-base=3.8.0=py39hb47e01b_0
+ - matplotlib-inline=0.1.6=py39hecd8cb5_0
+ - mdit-py-plugins=0.3.0=py39hecd8cb5_0
+ - mdurl=0.1.0=py39hecd8cb5_0
+ - mistune=2.0.4=py39hecd8cb5_0
+ - multipledispatch=0.6.0=py39hecd8cb5_0
+ - nbclient=0.8.0=py39hecd8cb5_0
+ - nbconvert=7.10.0=py39hecd8cb5_0
+ - nbformat=5.9.2=py39hecd8cb5_0
+ - ncurses=6.4=hcec6c5f_0
+ - nest-asyncio=1.5.6=py39hecd8cb5_0
+ - notebook-shim=0.2.3=py39hecd8cb5_0
+ - notebook=7.0.6=py39hecd8cb5_0
+ - numba=0.58.1=py39hcec6c5f_0
+ - numexpr=2.8.7=py39hf6dca73_0
+ - numpy-base=1.26.2=py39hd8f4981_0
+ - numpy=1.26.2=py39hf6dca73_0
+ - openjpeg=2.4.0=h66ea3da_0
+ - openssl=1.1.1w=hca72f7f_0
+ - orc=1.7.4=h995b336_1
+ - overrides=7.4.0=py39hecd8cb5_0
+ - packaging=23.1=py39hecd8cb5_0
+ - pandas=2.1.1=py39h3ea8b11_0
+ - panel=1.3.1=py39hecd8cb5_0
+ - param=2.0.1=py39hecd8cb5_0
+ - partd=1.4.1=py39hecd8cb5_0
+ - pillow=10.0.1=py39h7d39338_0
+ - pip=23.3.1=py39hecd8cb5_0
+ - platformdirs=3.10.0=py39hecd8cb5_0
+ - prometheus_client=0.14.1=py39hecd8cb5_0
+ - prompt-toolkit=3.0.36=py39hecd8cb5_0
+ - psutil=5.9.0=py39hca72f7f_0
+ - pyarrow=11.0.0=py39he65a03e_1
+ - pyct=0.5.0=py39hecd8cb5_0
+ - pygments=2.15.1=py39hecd8cb5_1
+ - pyopenssl=23.2.0=py39hecd8cb5_0
+ - pyparsing=3.0.9=py39hecd8cb5_0
+ - pysocks=1.7.1=py39hecd8cb5_0
+ - python-fastjsonschema=2.16.2=py39hecd8cb5_0
+ - python-json-logger=2.0.7=py39hecd8cb5_0
+ - python=3.9.0=h88f2d9e_2
+ - pytz=2023.3.post1=py39hecd8cb5_0
+ - pyviz_comms=3.0.0=py39hecd8cb5_0
+ - pyyaml=6.0.1=py39h6c40b1e_0
+ - pyzmq=25.1.0=py39hcec6c5f_0
+ - re2=2022.04.01=he9d5cce_0
+ - readline=8.2=hca72f7f_0
+ - referencing=0.30.2=py39hecd8cb5_0
+ - requests=2.31.0=py39hecd8cb5_0
+ - rfc3339-validator=0.1.4=py39hecd8cb5_0
+ - rfc3986-validator=0.1.1=py39hecd8cb5_0
+ - rpds-py=0.10.6=py39hf2ad997_0
+ - scipy=1.11.4=py39ha516a68_0
+ - send2trash=1.8.2=py39hecd8cb5_0
+ - setuptools=68.0.0=py39hecd8cb5_0
+ - snappy=1.1.9=he9d5cce_0
+ - sniffio=1.2.0=py39hecd8cb5_1
+ - soupsieve=2.5=py39hecd8cb5_0
+ - sqlite=3.41.2=h6c40b1e_0
+ - tbb=2021.8.0=ha357a0b_0
+ - terminado=0.17.1=py39hecd8cb5_0
+ - tinycss2=1.2.1=py39hecd8cb5_0
+ - tk=8.6.12=h5d9f67b_0
+ - tomli=2.0.1=py39hecd8cb5_0
+ - toolz=0.12.0=py39hecd8cb5_0
+ - tornado=6.3.3=py39h6c40b1e_0
+ - tqdm=4.65.0=py39h01d92e1_0
+ - traitlets=5.7.1=py39hecd8cb5_0
+ - typing-extensions=4.7.1=py39hecd8cb5_0
+ - typing_extensions=4.7.1=py39hecd8cb5_0
+ - uc-micro-py=1.0.1=py39hecd8cb5_0
+ - urllib3=1.26.18=py39hecd8cb5_0
+ - utf8proc=2.6.1=h9ed2024_0
+ - webencodings=0.5.1=py39hecd8cb5_1
+ - websocket-client=0.58.0=py39hecd8cb5_4
+ - wheel=0.41.2=py39hecd8cb5_0
+ - xarray=2023.6.0=py39hecd8cb5_0
+ - xyzservices=2022.9.0=py39hecd8cb5_1
+ - xz=5.4.5=h6c40b1e_0
+ - yaml=0.2.5=haf1e3a3_0
+ - zeromq=4.3.4=h23ab428_0
+ - zipp=3.11.0=py39hecd8cb5_0
+ - zlib=1.2.13=h4dc903c_0
+ - zstd=1.5.5=hc035e20_0
+ osx-arm64:
+ - abseil-cpp=20211102.0=hc377ac9_0
+ - anyio=3.5.0=py39hca03da5_0
+ - appnope=0.1.2=py39hca03da5_1001
+ - argon2-cffi-bindings=21.2.0=py39h1a28f6b_0
+ - arrow-cpp=11.0.0=he3f21e0_2
+ - async-lru=2.0.4=py39hca03da5_0
+ - attrs=23.1.0=py39hca03da5_0
+ - aws-c-common=0.6.8=h80987f9_1
+ - aws-c-event-stream=0.1.6=h313beb8_6
+ - aws-checksums=0.1.11=h80987f9_2
+ - aws-sdk-cpp=1.8.185=h4a942e0_0
+ - babel=2.11.0=py39hca03da5_0
+ - beautifulsoup4=4.12.2=py39hca03da5_0
+ - boost-cpp=1.82.0=h48ca7d4_2
+ - bottleneck=1.3.5=py39heec5a64_0
+ - brotli-bin=1.0.9=h1a28f6b_7
+ - brotli-python=1.0.9=py39hc377ac9_7
+ - brotli=1.0.9=h1a28f6b_7
+ - bzip2=1.0.8=h620ffc9_4
+ - c-ares=1.19.1=h80987f9_0
+ - ca-certificates=2023.08.22=hca03da5_0
+ - certifi=2023.11.17=py39hca03da5_0
+ - cffi=1.15.1=py39h22df2f2_0
+ - click=8.1.7=py39hca03da5_0
+ - cloudpickle=2.2.1=py39hca03da5_0
+ - colorcet=3.0.1=py39hca03da5_0
+ - comm=0.1.2=py39hca03da5_0
+ - contourpy=1.2.0=py39h48ca7d4_0
+ - cryptography=41.0.3=py39h3c57c4d_0
+ - dask-core=2023.11.0=py39hca03da5_0
+ - datashader=0.16.0=py39hca03da5_0
+ - debugpy=1.6.7=py39h313beb8_0
+ - exceptiongroup=1.0.4=py39hca03da5_0
+ - freetype=2.12.1=h1192e45_0
+ - fsspec=2023.10.0=py39hca03da5_0
+ - gflags=2.2.2=hc377ac9_0
+ - giflib=5.2.1=h80987f9_3
+ - glog=0.5.0=hc377ac9_0
+ - grpc-cpp=1.48.2=h877324c_0
+ - holoviews=1.18.1=py39hca03da5_0
+ - icu=73.1=h313beb8_0
+ - idna=3.4=py39hca03da5_0
+ - importlib-metadata=6.0.0=py39hca03da5_0
+ - importlib_resources=6.1.0=py39hca03da5_0
+ - ipykernel=6.25.0=py39h33ce5c2_0
+ - ipython=8.15.0=py39hca03da5_0
+ - jedi=0.18.1=py39hca03da5_1
+ - jinja2=3.1.2=py39hca03da5_0
+ - jpeg=9e=h80987f9_1
+ - jsonschema-specifications=2023.7.1=py39hca03da5_0
+ - jsonschema=4.19.2=py39hca03da5_0
+ - jupyter-lsp=2.2.0=py39hca03da5_0
+ - jupyter_client=8.6.0=py39hca03da5_0
+ - jupyter_core=5.5.0=py39hca03da5_0
+ - jupyter_events=0.8.0=py39hca03da5_0
+ - jupyter_server=2.10.0=py39hca03da5_0
+ - jupyter_server_terminals=0.4.4=py39hca03da5_1
+ - jupyterlab=4.0.8=py39hca03da5_0
+ - jupyterlab_server=2.25.1=py39hca03da5_0
+ - kiwisolver=1.4.4=py39h313beb8_0
+ - krb5=1.20.1=h8380606_1
+ - lcms2=2.12=hba8e193_0
+ - lerc=3.0=hc377ac9_0
+ - libboost=1.82.0=h0bc93f9_2
+ - libbrotlicommon=1.0.9=h1a28f6b_7
+ - libbrotlidec=1.0.9=h1a28f6b_7
+ - libbrotlienc=1.0.9=h1a28f6b_7
+ - libcurl=8.2.1=h0f1d93c_0
+ - libcxx=14.0.6=h848a8c0_0
+ - libdeflate=1.17=h80987f9_1
+ - libedit=3.1.20221030=h80987f9_0
+ - libev=4.33=h1a28f6b_1
+ - libevent=2.1.12=hf27765b_0
+ - libffi=3.3=hc377ac9_2
+ - libgfortran5=11.3.0=h009349e_28
+ - libgfortran=5.0.0=11_3_0_hca03da5_28
+ - libiconv=1.16=h1a28f6b_2
+ - libllvm14=14.0.6=h4b41812_0
+ - libnghttp2=1.52.0=h10c0552_1
+ - libopenblas=0.3.21=h269037a_0
+ - libpng=1.6.39=h80987f9_0
+ - libprotobuf=3.20.3=h514c7bf_0
+ - libsodium=1.0.18=h1a28f6b_0
+ - libssh2=1.10.0=h449679c_2
+ - libthrift=0.15.0=h169de6a_2
+ - libtiff=4.5.1=h313beb8_0
+ - libwebp-base=1.3.2=h80987f9_0
+ - libwebp=1.3.2=ha3663a8_0
+ - linkify-it-py=2.0.0=py39hca03da5_0
+ - llvm-openmp=14.0.6=hc6e5704_0
+ - llvmlite=0.41.0=py39h514c7bf_0
+ - locket=1.0.0=py39hca03da5_0
+ - lz4-c=1.9.4=h313beb8_0
+ - markdown-it-py=2.2.0=py39hca03da5_1
+ - markdown=3.4.1=py39hca03da5_0
+ - markupsafe=2.1.1=py39h1a28f6b_0
+ - matplotlib-base=3.8.0=py39h46d7db6_0
+ - matplotlib-inline=0.1.6=py39hca03da5_0
+ - mdit-py-plugins=0.3.0=py39hca03da5_0
+ - mdurl=0.1.0=py39hca03da5_0
+ - mistune=2.0.4=py39hca03da5_0
+ - multipledispatch=0.6.0=py39hca03da5_0
+ - nbclient=0.8.0=py39hca03da5_0
+ - nbconvert=7.10.0=py39hca03da5_0
+ - nbformat=5.9.2=py39hca03da5_0
+ - ncurses=6.4=h313beb8_0
+ - nest-asyncio=1.5.6=py39hca03da5_0
+ - notebook-shim=0.2.3=py39hca03da5_0
+ - notebook=7.0.6=py39hca03da5_0
+ - numba=0.58.1=py39h313beb8_0
+ - numexpr=2.8.7=py39hecc3335_0
+ - numpy-base=1.26.2=py39ha9811e2_0
+ - numpy=1.26.2=py39h3b2db8e_0
+ - openjpeg=2.3.0=h7a6adac_2
+ - openssl=1.1.1w=h1a28f6b_0
+ - orc=1.7.4=hdca1487_1
+ - overrides=7.4.0=py39hca03da5_0
+ - packaging=23.1=py39hca03da5_0
+ - pandas=2.1.1=py39h46d7db6_0
+ - panel=1.3.1=py39hca03da5_0
+ - param=2.0.1=py39hca03da5_0
+ - partd=1.4.1=py39hca03da5_0
+ - pillow=10.0.1=py39h3b245a6_0
+ - pip=23.3.1=py39hca03da5_0
+ - platformdirs=3.10.0=py39hca03da5_0
+ - prometheus_client=0.14.1=py39hca03da5_0
+ - prompt-toolkit=3.0.36=py39hca03da5_0
+ - psutil=5.9.0=py39h1a28f6b_0
+ - pyarrow=11.0.0=py39hbfed03b_1
+ - pyct=0.5.0=py39hca03da5_0
+ - pygments=2.15.1=py39hca03da5_1
+ - pyopenssl=23.2.0=py39hca03da5_0
+ - pyparsing=3.0.9=py39hca03da5_0
+ - pysocks=1.7.1=py39hca03da5_0
+ - python-fastjsonschema=2.16.2=py39hca03da5_0
+ - python-json-logger=2.0.7=py39hca03da5_0
+ - python=3.9.0=h4b4120c_5_cpython
+ - pytz=2023.3.post1=py39hca03da5_0
+ - pyviz_comms=3.0.0=py39hca03da5_0
+ - pyyaml=6.0.1=py39h80987f9_0
+ - pyzmq=25.1.0=py39h313beb8_0
+ - re2=2022.04.01=hc377ac9_0
+ - readline=8.2=h1a28f6b_0
+ - referencing=0.30.2=py39hca03da5_0
+ - requests=2.31.0=py39hca03da5_0
+ - rfc3339-validator=0.1.4=py39hca03da5_0
+ - rfc3986-validator=0.1.1=py39hca03da5_0
+ - rpds-py=0.10.6=py39hf0e4da2_0
+ - scipy=1.11.4=py39h20cbe94_0
+ - send2trash=1.8.2=py39hca03da5_0
+ - setuptools=68.0.0=py39hca03da5_0
+ - snappy=1.1.9=hc377ac9_0
+ - sniffio=1.2.0=py39hca03da5_1
+ - soupsieve=2.5=py39hca03da5_0
+ - sqlite=3.41.2=h80987f9_0
+ - tbb=2021.8.0=h48ca7d4_0
+ - terminado=0.17.1=py39hca03da5_0
+ - tinycss2=1.2.1=py39hca03da5_0
+ - tk=8.6.12=hb8d0fd4_0
+ - tomli=2.0.1=py39hca03da5_0
+ - toolz=0.12.0=py39hca03da5_0
+ - tornado=6.3.3=py39h80987f9_0
+ - tqdm=4.65.0=py39h86d0a89_0
+ - traitlets=5.7.1=py39hca03da5_0
+ - typing-extensions=4.7.1=py39hca03da5_0
+ - typing_extensions=4.7.1=py39hca03da5_0
+ - uc-micro-py=1.0.1=py39hca03da5_0
+ - urllib3=1.26.18=py39hca03da5_0
+ - utf8proc=2.6.1=h1a28f6b_0
+ - webencodings=0.5.1=py39hca03da5_1
+ - websocket-client=0.58.0=py39hca03da5_4
+ - wheel=0.41.2=py39hca03da5_0
+ - xarray=2023.6.0=py39hca03da5_0
+ - xyzservices=2022.9.0=py39hca03da5_1
+ - xz=5.4.5=h80987f9_0
+ - yaml=0.2.5=h1a28f6b_0
+ - zeromq=4.3.4=hc377ac9_0
+ - zipp=3.11.0=py39hca03da5_0
+ - zlib=1.2.13=h5a0b063_0
+ - zstd=1.5.5=hd90d995_0
+ win-64:
+ - abseil-cpp=20211102.0=hd77b12b_0
+ - anyio=3.5.0=py39haa95532_0
+ - argon2-cffi-bindings=21.2.0=py39h2bbff1b_0
+ - arrow-cpp=11.0.0=h2c9b28c_2
+ - async-lru=2.0.4=py39haa95532_0
+ - attrs=23.1.0=py39haa95532_0
+ - aws-c-common=0.4.57=ha925a31_1
+ - aws-c-event-stream=0.1.6=hd77b12b_5
+ - aws-checksums=0.1.9=ha925a31_0
+ - aws-sdk-cpp=1.8.185=hd77b12b_0
+ - babel=2.11.0=py39haa95532_0
+ - beautifulsoup4=4.12.2=py39haa95532_0
+ - blas=1.0=mkl
+ - boost-cpp=1.82.0=h59b6b97_2
+ - bottleneck=1.3.5=py39h080aedc_0
+ - brotli-bin=1.0.9=h2bbff1b_7
+ - brotli-python=1.0.9=py39hd77b12b_7
+ - brotli=1.0.9=h2bbff1b_7
+ - bzip2=1.0.8=he774522_0
+ - c-ares=1.19.1=h2bbff1b_0
+ - ca-certificates=2023.08.22=haa95532_0
+ - certifi=2023.11.17=py39haa95532_0
+ - cffi=1.16.0=py39h2bbff1b_0
+ - click=8.1.7=py39haa95532_0
+ - cloudpickle=2.2.1=py39haa95532_0
+ - colorama=0.4.6=py39haa95532_0
+ - colorcet=3.0.1=py39haa95532_0
+ - comm=0.1.2=py39haa95532_0
+ - contourpy=1.2.0=py39h59b6b97_0
+ - cryptography=41.0.3=py39h3438e0d_0
+ - dask-core=2023.11.0=py39haa95532_0
+ - datashader=0.16.0=py39haa95532_0
+ - debugpy=1.6.7=py39hd77b12b_0
+ - exceptiongroup=1.0.4=py39haa95532_0
+ - freetype=2.12.1=ha860e81_0
+ - fsspec=2023.10.0=py39haa95532_0
+ - gflags=2.2.2=ha925a31_0
+ - giflib=5.2.1=h8cc25b3_3
+ - glog=0.5.0=hd77b12b_0
+ - grpc-cpp=1.48.2=hf108199_0
+ - holoviews=1.18.1=py39haa95532_0
+ - icc_rt=2022.1.0=h6049295_2
+ - idna=3.4=py39haa95532_0
+ - importlib-metadata=6.0.0=py39haa95532_0
+ - importlib_resources=6.1.0=py39haa95532_0
+ - intel-openmp=2023.1.0=h59b6b97_46320
+ - ipykernel=6.25.0=py39h9909e9c_0
+ - ipython=8.15.0=py39haa95532_0
+ - jedi=0.18.1=py39haa95532_1
+ - jinja2=3.1.2=py39haa95532_0
+ - jpeg=9e=h2bbff1b_1
+ - jsonschema-specifications=2023.7.1=py39haa95532_0
+ - jsonschema=4.19.2=py39haa95532_0
+ - jupyter-lsp=2.2.0=py39haa95532_0
+ - jupyter_client=8.6.0=py39haa95532_0
+ - jupyter_core=5.5.0=py39haa95532_0
+ - jupyter_events=0.8.0=py39haa95532_0
+ - jupyter_server=2.10.0=py39haa95532_0
+ - jupyter_server_terminals=0.4.4=py39haa95532_1
+ - jupyterlab=4.0.8=py39haa95532_0
+ - jupyterlab_server=2.25.1=py39haa95532_0
+ - kiwisolver=1.4.4=py39hd77b12b_0
+ - lerc=3.0=hd77b12b_0
+ - libboost=1.82.0=h3399ecb_2
+ - libbrotlicommon=1.0.9=h2bbff1b_7
+ - libbrotlidec=1.0.9=h2bbff1b_7
+ - libbrotlienc=1.0.9=h2bbff1b_7
+ - libcurl=8.4.0=h86230a5_0
+ - libdeflate=1.17=h2bbff1b_1
+ - libevent=2.1.12=hcc03200_0
+ - libpng=1.6.39=h8cc25b3_0
+ - libprotobuf=3.20.3=h23ce68f_0
+ - libsodium=1.0.18=h62dcd97_0
+ - libssh2=1.10.0=hcd4344a_2
+ - libthrift=0.15.0=he49ee6e_2
+ - libtiff=4.5.1=hd77b12b_0
+ - libwebp-base=1.3.2=h2bbff1b_0
+ - libwebp=1.3.2=hbc33d0d_0
+ - linkify-it-py=2.0.0=py39haa95532_0
+ - llvmlite=0.41.0=py39hf2fb9eb_0
+ - locket=1.0.0=py39haa95532_0
+ - lz4-c=1.9.4=h2bbff1b_0
+ - markdown-it-py=2.2.0=py39haa95532_1
+ - markdown=3.4.1=py39haa95532_0
+ - markupsafe=2.1.1=py39h2bbff1b_0
+ - matplotlib-base=3.8.0=py39h4ed8f06_0
+ - matplotlib-inline=0.1.6=py39haa95532_0
+ - mdit-py-plugins=0.3.0=py39haa95532_0
+ - mdurl=0.1.0=py39haa95532_0
+ - mistune=2.0.4=py39haa95532_0
+ - mkl-service=2.4.0=py39h2bbff1b_1
+ - mkl=2023.1.0=h6b88ed4_46358
+ - mkl_fft=1.3.8=py39h2bbff1b_0
+ - mkl_random=1.2.4=py39h59b6b97_0
+ - multipledispatch=0.6.0=py39haa95532_0
+ - nbclient=0.8.0=py39haa95532_0
+ - nbconvert=7.10.0=py39haa95532_0
+ - nbformat=5.9.2=py39haa95532_0
+ - nest-asyncio=1.5.6=py39haa95532_0
+ - notebook-shim=0.2.3=py39haa95532_0
+ - notebook=7.0.6=py39haa95532_0
+ - numba=0.58.1=py39hd77b12b_0
+ - numexpr=2.8.7=py39h2cd9be0_0
+ - numpy-base=1.26.2=py39h65a83cf_0
+ - numpy=1.26.2=py39h055cbcc_0
+ - openjpeg=2.4.0=h4fc8c34_0
+ - openssl=1.1.1w=h2bbff1b_0
+ - orc=1.7.4=h623e30f_1
+ - overrides=7.4.0=py39haa95532_0
+ - packaging=23.1=py39haa95532_0
+ - pandas=2.1.1=py39h4ed8f06_0
+ - panel=1.3.1=py39haa95532_0
+ - param=2.0.1=py39haa95532_0
+ - partd=1.4.1=py39haa95532_0
+ - pillow=10.0.1=py39h045eedc_0
+ - pip=23.3.1=py39haa95532_0
+ - platformdirs=3.10.0=py39haa95532_0
+ - prometheus_client=0.14.1=py39haa95532_0
+ - prompt-toolkit=3.0.36=py39haa95532_0
+ - psutil=5.9.0=py39h2bbff1b_0
+ - pyarrow=11.0.0=py39h790e06d_1
+ - pyct=0.5.0=py39haa95532_0
+ - pygments=2.15.1=py39haa95532_1
+ - pyopenssl=23.2.0=py39haa95532_0
+ - pyparsing=3.0.9=py39haa95532_0
+ - pysocks=1.7.1=py39haa95532_0
+ - python-fastjsonschema=2.16.2=py39haa95532_0
+ - python-json-logger=2.0.7=py39haa95532_0
+ - python=3.9.0=h6244533_2
+ - pytz=2023.3.post1=py39haa95532_0
+ - pyviz_comms=3.0.0=py39haa95532_0
+ - pywin32=305=py39h2bbff1b_0
+ - pywinpty=2.0.10=py39h5da7b33_0
+ - pyyaml=6.0.1=py39h2bbff1b_0
+ - pyzmq=25.1.0=py39hd77b12b_0
+ - re2=2022.04.01=hd77b12b_0
+ - referencing=0.30.2=py39haa95532_0
+ - requests=2.31.0=py39haa95532_0
+ - rfc3339-validator=0.1.4=py39haa95532_0
+ - rfc3986-validator=0.1.1=py39haa95532_0
+ - rpds-py=0.10.6=py39h062c2fa_0
+ - scipy=1.11.4=py39h309d312_0
+ - send2trash=1.8.2=py39haa95532_0
+ - setuptools=68.0.0=py39haa95532_0
+ - snappy=1.1.9=h6c2663c_0
+ - sniffio=1.2.0=py39haa95532_1
+ - soupsieve=2.5=py39haa95532_0
+ - sqlite=3.41.2=h2bbff1b_0
+ - tbb=2021.8.0=h59b6b97_0
+ - terminado=0.17.1=py39haa95532_0
+ - tinycss2=1.2.1=py39haa95532_0
+ - tk=8.6.12=h2bbff1b_0
+ - tomli=2.0.1=py39haa95532_0
+ - toolz=0.12.0=py39haa95532_0
+ - tornado=6.3.3=py39h2bbff1b_0
+ - tqdm=4.65.0=py39hd4e2768_0
+ - traitlets=5.7.1=py39haa95532_0
+ - typing-extensions=4.7.1=py39haa95532_0
+ - typing_extensions=4.7.1=py39haa95532_0
+ - uc-micro-py=1.0.1=py39haa95532_0
+ - urllib3=1.26.18=py39haa95532_0
+ - utf8proc=2.6.1=h2bbff1b_0
+ - vc=14.2=h21ff451_1
+ - vs2015_runtime=14.27.29016=h5e58377_2
+ - webencodings=0.5.1=py39haa95532_1
+ - websocket-client=0.58.0=py39haa95532_4
+ - wheel=0.41.2=py39haa95532_0
+ - win_inet_pton=1.1.0=py39haa95532_0
+ - winpty=0.4.3=4
+ - xarray=2023.6.0=py39haa95532_0
+ - xyzservices=2022.9.0=py39haa95532_1
+ - xz=5.4.5=h8cc25b3_0
+ - yaml=0.2.5=he774522_0
+ - zeromq=4.3.4=hd77b12b_0
+ - zipp=3.11.0=py39haa95532_0
+ - zlib=1.2.13=h8cc25b3_0
+ - zstd=1.5.5=hd43e919_0
diff --git a/t_sne_roots/anaconda-project.yml b/t_sne_roots/anaconda-project.yml
new file mode 100644
index 000000000..3aeb1b881
--- /dev/null
+++ b/t_sne_roots/anaconda-project.yml
@@ -0,0 +1,79 @@
+name: t_sne_roots
+description: Dimensionality reduction of multi-lingual dataset with datashaded instant hover
+
+examples_config:
+ # Creation date following the YYYY-MM-DD format
+ created: 2023-07-28
+ maintainers:
+ - "jlstevens"
+ labels:
+ - "datashader"
+ - "panel"
+ notebooks_to_skip:
+ - t_sne_roots_datashaded.ipynb
+ ### OPTIONAL ###
+
+ title: "t-SNE ROOTS"
+ # Listed deployments will by default automatically be started.
+ # Maximum number of deployments is 2.
+ # Each deployment must declare the command it deploys, options
+ # include "notebook" or "dashboard".
+ deployments:
+ # Will be deployed at {projname_with_hyphens}-notebook.pyviz.demo.anaconda.com
+ - command: dashboard
+ resource_profile: medium
+ auto_deploy: false
+
+ # to build the website (e.g. too long or require too much data).
+ # This indicates the system not to run them.
+ skip_notebooks_evaluation: false
+ no_data_ingestion: false
+ gh_runner: "ubuntu-latest"
+
+
+# required: (needed internally)
+user_fields: [examples_config]
+
+# required: list of the channels needed to solve the environment
+channels:
+- defaults
+- conda-forge
+
+packages: &pkgs
+- notebook >=7
+# then list all your dependencies, including Python itself
+- python ==3.9
+- holoviews >= 1.17.0
+- datashader >= 0.15.1
+- pyarrow
+- pyarrow-hotfix
+- bokeh ==3.3.2
+- numba >= 0.57
+
+
+dependencies: *pkgs
+
+
+commands:
+ # if you intend to run notebooks, set the `notebook` command
+ dashboard:
+ # for a deployment, the `--rest-session-info --session-history -1` options are required
+ unix: panel serve --rest-session-info --session-history -1 t_sne_roots.ipynb
+ supports_http_options: true
+
+
+# optional downloads
+downloads:
+ DATA:
+ url: https://huggingface.co/datasets/cakiki/roots-tsne-data/resolve/main/data/train-00000-of-00001-9a434d9cf7fd233e.parquet # Keep our own copy?
+ description: |
+ Trained data using t-SNE on ROOTS by Christopher Akiki
+ # The output must be in the data/ subfolder
+ filename: data/train-00000-of-00001-9a434d9cf7fd233e.parquet
+
+# required: supported plaforms
+platforms:
+- linux-64
+- osx-64
+- win-64
+- osx-arm64
diff --git a/t_sne_roots/t_sne_roots.ipynb b/t_sne_roots/t_sne_roots.ipynb
new file mode 100644
index 000000000..bb45e7198
--- /dev/null
+++ b/t_sne_roots/t_sne_roots.ipynb
@@ -0,0 +1,158 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "286d2e98-9f33-4e1e-bba4-f526360dfc59",
+ "metadata": {},
+ "source": [
+ "# Interactive t-SNE ROOTS dimensionality reduction"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "3d774823",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import colorcet as cc\n",
+ "import holoviews as hv\n",
+ "import panel as pn\n",
+ "\n",
+ "import warnings\n",
+ "warnings.filterwarnings(action=\"ignore\")\n",
+ "import datashader as ds\n",
+ "from holoviews.operation.datashader import rasterize\n",
+ "pn.extension()\n",
+ "hv.extension('bokeh')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9deb58ad-1c26-440c-a622-80a79159102c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "*Visualization of t-Distributed Stochastic Neighbor Embedding of ROOTS language Corpus.*\n",
+ "\n",
+ "Trained data from Christopher Akiki (dataset `cakiki/roots-tsne-data` on Hugging Face. A version of this notebook that runs color-mixing on the server-side can be found [here](./t_sne_roots_datashaded.ipynb)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c46d5abb-2a8c-4533-9e30-9970bf20e015",
+ "metadata": {},
+ "source": [
+ "## Load the data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6bf4b1c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tsne_embedding = pd.read_parquet('./data/train-00000-of-00001-9a434d9cf7fd233e.parquet')\n",
+ "df = pd.DataFrame(data=tsne_embedding, columns=['x','y','language'])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d56df973-74b8-44af-a80b-cda8d304b4c6",
+ "metadata": {},
+ "source": [
+ "## Datashade and add hover layer\n",
+ "\n",
+ "Note that until client-side colormixing is supported, the `datashade` operation is used with an invisible hover layer overlaid on top."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b3f9e6b7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "points = hv.Points(df, ['x','y'], ['language'])\n",
+ "op = rasterize(points,aggregator=ds.by('language', ds.count())).opts(\n",
+ " show_legend=False, frame_width=600, aspect=1, cnorm='eq_hist', cmap=cc.glasbey_light[:47])\n",
+ "hover_layer = rasterize(points, selector=ds.first(\"x\"), x_sampling=2, y_sampling=2).opts(tools=[\"hover\"], alpha=0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5ac2a4f4-84fa-438c-b049-0a2f678c5270",
+ "metadata": {},
+ "source": [
+ "### Render"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b5f9f99b-afde-46d1-af64-b3a98a306bc5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "op * hover_layer"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b2ab76e-b3f4-4c15-8295-2a1285d0ef62",
+ "metadata": {},
+ "source": [
+ "### Build a small dashboard with panel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5bb031a1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "text = \"\"\"\n",
+ "### Visualization of t-Distributed Stochastic Neighbor Embedding of ROOTS language Corpus.
Trained data from Christopher Akiki (dataset `cakiki/roots-tsne-data` on Hugging Face\n",
+ "\"\"\"\n",
+ "\n",
+ "template = pn.template.FastListTemplate(\n",
+ " title=\"t-SNE clustering of ROOTS language corpus\"\n",
+ ")\n",
+ "\n",
+ "template.main.append(\n",
+ " pn.Column(\n",
+ " pn.pane.Markdown(text),\n",
+ " pn.Row(pn.HSpacer(), \n",
+ " op * hover_layer,\n",
+ " pn.HSpacer())\n",
+ " )\n",
+ ")\n",
+ "template.servable();"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/t_sne_roots/t_sne_roots_datashaded.ipynb b/t_sne_roots/t_sne_roots_datashaded.ipynb
new file mode 100644
index 000000000..140e2ae7d
--- /dev/null
+++ b/t_sne_roots/t_sne_roots_datashaded.ipynb
@@ -0,0 +1,163 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "286d2e98-9f33-4e1e-bba4-f526360dfc59",
+ "metadata": {},
+ "source": [
+ "# Interactive t-SNE ROOTS dimensionality reduction (*datashaded*)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "975b035c-46bb-40ca-ae68-980d61e4cd97",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import colorcet as cc\n",
+ "import holoviews as hv\n",
+ "import panel as pn\n",
+ "\n",
+ "import warnings\n",
+ "warnings.filterwarnings(action=\"ignore\")\n",
+ "import datashader as ds\n",
+ "from holoviews.operation.datashader import datashade, rasterize, dynspread\n",
+ "hv.extension('bokeh')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9deb58ad-1c26-440c-a622-80a79159102c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "*Visualization of t-Distributed Stochastic Neighbor Embedding of ROOTS language Corpus.*\n",
+ "\n",
+ "Trained data from Christopher Akiki (dataset `cakiki/roots-tsne-data` on Hugging Face \n",
+ "\n",
+ "A version of this notebook that runs color-mixing on the client-side can be found [here](./t_sne_roots.ipynb). Here are the key differences between the datashaded and rasterized versions:\n",
+ "\n",
+ "* The rasterized version is color mixed in the browser, allowing enhanced interactivity (e.g. colorbars)\n",
+ "* The rasterized version returns an `ImageStack` while the datashaded version returns an `RGB`: the former retains the data statistics. \n",
+ "* The datashaded version uses `dynspread` as `ImageStack` does not yet support spreading.\n",
+ "\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c46d5abb-2a8c-4533-9e30-9970bf20e015",
+ "metadata": {},
+ "source": [
+ "## Load the data"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "6bf4b1c8",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tsne_embedding = pd.read_parquet('./data/train-00000-of-00001-9a434d9cf7fd233e.parquet')\n",
+ "df = pd.DataFrame(data=tsne_embedding, columns=['x','y','language'])\n",
+ "df.head()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d56df973-74b8-44af-a80b-cda8d304b4c6",
+ "metadata": {},
+ "source": [
+ "## Datashade and add hover layer\n",
+ "\n",
+ "Note that until client-side colormixing is supported, the `datashade` operation is used with an invisible hover layer overlaid on top."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b3f9e6b7",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "points = hv.Points(df, ['x','y'], ['language'])\n",
+ "op = datashade(points, color_key=cc.glasbey_light,\n",
+ " aggregator=ds.by('language', ds.count())).opts(show_legend=False, bgcolor='black', frame_width=600, aspect=1)\n",
+ "hover_layer = rasterize(points, selector=ds.first(\"x\"), x_sampling=2, y_sampling=2).opts(tools=[\"hover\"], alpha=0)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5ac2a4f4-84fa-438c-b049-0a2f678c5270",
+ "metadata": {},
+ "source": [
+ "### Render"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "b5f9f99b-afde-46d1-af64-b3a98a306bc5",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "dynspread(op) * hover_layer"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b2ab76e-b3f4-4c15-8295-2a1285d0ef62",
+ "metadata": {},
+ "source": [
+ "### Build a small dashboard with panel"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "5bb031a1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "text = \"\"\"\n",
+ "### Visualization of t-Distributed Stochastic Neighbor Embedding of ROOTS language Corpus.
Trained data from Christopher Akiki (dataset `cakiki/roots-tsne-data` on Hugging Face\n",
+ "\"\"\"\n",
+ "\n",
+ "template = pn.template.FastListTemplate(\n",
+ " title=\"t-SNE clustering of ROOTS language corpus\"\n",
+ ")\n",
+ "\n",
+ "template.main.append(\n",
+ " pn.Column(\n",
+ " pn.pane.Markdown(text),\n",
+ " pn.Row(pn.HSpacer(), dynspread(op) * hover_layer, pn.HSpacer())\n",
+ " )\n",
+ ")\n",
+ "template.servable();"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.9.0"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/t_sne_roots/thumbnails/t_sne_roots.png b/t_sne_roots/thumbnails/t_sne_roots.png
new file mode 100644
index 000000000..f341c5cda
Binary files /dev/null and b/t_sne_roots/thumbnails/t_sne_roots.png differ
diff --git a/test_data/t_sne_roots/train-00000-of-00001-9a434d9cf7fd233e.parquet b/test_data/t_sne_roots/train-00000-of-00001-9a434d9cf7fd233e.parquet
new file mode 100644
index 000000000..c696af1dc
Binary files /dev/null and b/test_data/t_sne_roots/train-00000-of-00001-9a434d9cf7fd233e.parquet differ