diff --git a/gapminders/anaconda-project-lock.yml b/gapminders/anaconda-project-lock.yml index c1efb00c5..69f29e7bd 100644 --- a/gapminders/anaconda-project-lock.yml +++ b/gapminders/anaconda-project-lock.yml @@ -10,528 +10,595 @@ # Set to false to ignore locked versions. # locking_enabled: true - -# -# A key goes in here for each env spec. -# env_specs: - test: - locked: true - env_spec_hash: a8d706af59fa3a30148011cc332c2cc035881c84 - platforms: - - linux-64 - - osx-64 - - win-64 - packages: - all: - - altair=3.3.0=py37_0 - - async_generator=1.10=py_0 - - attrs=21.2.0=pyhd8ed1ab_0 - - backcall=0.2.0=pyh9f0ad1d_0 - - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0 - - backports=1.0=py_2 - - bleach=3.3.1=pyhd8ed1ab_0 - - bokeh=2.2.1=py37hc8dfbb8_1 - - charset-normalizer=2.0.0=pyhd8ed1ab_0 - - colorcet=2.0.6=pyhd8ed1ab_0 - - cycler=0.10.0=py_2 - - decorator=5.0.9=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - entrypoints=0.3=pyhd8ed1ab_1003 - - holoviews=1.14.1=pyhd3deb0d_0 - - hvplot=0.7.0=pyhd3deb0d_0 - - idna=3.1=pyhd3deb0d_0 - - ipython_genutils=0.2.0=py_1 - - jinja2=3.0.1=pyhd8ed1ab_0 - - jsonschema=3.2.0=pyhd8ed1ab_3 - - jupyter_client=6.1.12=pyhd8ed1ab_0 - - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0 - - markdown=3.3.4=pyhd8ed1ab_0 - - matplotlib-inline=0.1.2=pyhd8ed1ab_2 - - nbclient=0.5.3=pyhd8ed1ab_0 - - nbformat=5.1.3=pyhd8ed1ab_0 - - nest-asyncio=1.5.1=pyhd8ed1ab_0 - - notebook=5.7.8=py37_1 - - olefile=0.46=pyh9f0ad1d_1 - - packaging=21.0=pyhd8ed1ab_0 - - pandocfilters=1.4.2=py_1 - - panel=0.10.2=pyhd8ed1ab_0 - - param=1.10.0=py_0 - - parso=0.8.2=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pip=21.2.1=pyhd8ed1ab_0 - - plotly=5.1.0=pyhd8ed1ab_1 - - prometheus_client=0.11.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.19=pyha770c72_0 - - pycparser=2.20=pyh9f0ad1d_2 - - pyct-core=0.4.6=py_0 - - pyct=0.4.6=py_0 - - pygments=2.9.0=pyhd8ed1ab_0 - - pyopenssl=20.0.1=pyhd8ed1ab_0 - - pyparsing=2.4.7=pyh9f0ad1d_0 - - python-dateutil=2.8.2=pyhd8ed1ab_0 - - python_abi=3.7=2_cp37m - - pytz=2021.1=pyhd8ed1ab_0 - - pyviz_comms=2.1.0=pyhd8ed1ab_0 - - requests=2.26.0=pyhd8ed1ab_0 - - send2trash=1.7.1=pyhd8ed1ab_0 - - six=1.16.0=pyh6c4a22f_0 - - tenacity=8.0.1=pyhd8ed1ab_0 - - testpath=0.5.0=pyhd8ed1ab_0 - - toolz=0.11.1=py_0 - - tqdm=4.61.2=pyhd8ed1ab_1 - - traitlets=5.0.5=py_0 - - typing_extensions=3.10.0.0=pyha770c72_0 - - urllib3=1.26.6=pyhd8ed1ab_0 - - wcwidth=0.2.5=pyh9f0ad1d_2 - - webencodings=0.5.1=py_1 - - wheel=0.36.2=pyhd3deb0d_0 - - zipp=3.5.0=pyhd8ed1ab_0 - unix: - - libblas=3.9.0=10_openblas - - libcblas=3.9.0=10_openblas - - liblapack=3.9.0=10_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 - - brotlipy=0.7.0=py37h5e8e339_1001 - - ca-certificates=2021.5.30=ha878542_0 - - certifi=2021.5.30=py37h89c1867_0 - - cffi=1.14.6=py37hc58025e_0 - - chardet=4.0.0=py37h89c1867_1 - - cryptography=3.4.7=py37h5d9358c_0 - - freetype=2.10.4=h0708190_1 - - importlib-metadata=4.6.1=py37h89c1867_0 - - ipykernel=5.5.5=py37h085eea5_0 - - ipython=7.25.0=py37h085eea5_1 - - jbig=2.1=h7f98852_2003 - - jedi=0.18.0=py37h89c1867_2 - - jpeg=9d=h36c2ea0_0 - - jupyter_core=4.7.1=py37h89c1867_0 - - kiwisolver=1.3.1=py37h2527ec5_1 - - lcms2=2.12=hddcbb42_0 - - ld_impl_linux-64=2.36.1=hea4e1c9_2 - - lerc=2.2.1=h9c3ff4c_0 - - libdeflate=1.7=h7f98852_5 - - libffi=3.3=h58526e2_2 - - libgcc-ng=11.1.0=hc902ee8_4 - - libgfortran-ng=11.1.0=h69a702a_4 - - libgfortran5=11.1.0=h6c583b3_4 - - libgomp=11.1.0=hc902ee8_4 - - libopenblas=0.3.17=pthreads_h8fe5266_1 - - libpng=1.6.37=h21135ba_2 - - libsodium=1.0.18=h36c2ea0_1 - - libstdcxx-ng=11.1.0=h56837e0_4 - - libtiff=4.3.0=hf544144_1 - - libwebp-base=1.2.0=h7f98852_2 - - lz4-c=1.9.3=h9c3ff4c_0 - - markupsafe=2.0.1=py37h5e8e339_0 - - matplotlib-base=3.4.2=py37hdd32ed1_0 - - mistune=0.8.4=py37h5e8e339_1004 - - nbconvert=6.1.0=py37h89c1867_0 - - ncurses=6.2=h58526e2_4 - - numpy=1.21.1=py37h038b26d_0 - - openjpeg=2.4.0=hb52868f_1 - - openssl=1.1.1k=h7f98852_0 - - pandas=1.2.5=py37h219a48f_0 - - pandoc=2.14.1=h7f98852_0 - - pillow=8.3.1=py37h0f21c89_0 - - pyrsistent=0.17.3=py37h5e8e339_2 - - pysocks=1.7.1=py37h89c1867_3 - - python=3.7.10=hffdb5ce_100_cpython - - pyyaml=5.4.1=py37h5e8e339_0 - - pyzmq=22.1.0=py37h336d617_0 - - readline=8.1=h46c0cb4_0 - - setuptools=49.6.0=py37h89c1867_3 - - sqlite=3.36.0=h9cd32fc_0 - - terminado=0.10.1=py37h89c1867_0 - - tk=8.6.10=h21135ba_1 - - tornado=6.1=py37h5e8e339_1 - - xz=5.2.5=h516909a_1 - - yaml=0.2.5=h516909a_0 - - zeromq=4.3.4=h9c3ff4c_0 - - zlib=1.2.11=h516909a_1010 - - zstd=1.5.0=ha95c52a_0 - osx-64: - - appnope=0.1.2=py37hf985489_1 - - brotlipy=0.7.0=py37h271585c_1001 - - ca-certificates=2021.5.30=h033912b_0 - - certifi=2021.5.30=py37hf985489_0 - - cffi=1.14.6=py37hda351d9_0 - - chardet=4.0.0=py37hf985489_1 - - cryptography=3.4.7=py37hce4a858_0 - - freetype=2.10.4=h4cff582_1 - - importlib-metadata=4.6.1=py37hf985489_0 - - ipykernel=5.5.5=py37h85f7c60_0 - - ipython=7.25.0=py37h85f7c60_1 - - jbig=2.1=h0d85af4_2003 - - jedi=0.18.0=py37hf985489_2 - - jpeg=9d=hbcb3906_0 - - jupyter_core=4.7.1=py37hf985489_0 - - kiwisolver=1.3.1=py37h737db71_1 - - lcms2=2.12=h577c468_0 - - lerc=2.2.1=h046ec9c_0 - - libcxx=12.0.1=habf9029_0 - - libdeflate=1.7=h35c211d_5 - - libffi=3.3=h046ec9c_2 - - libgfortran5=9.3.0=h6c81a4c_23 - - libgfortran=5.0.0=9_3_0_h6c81a4c_23 - - libopenblas=0.3.17=openmp_h3351f45_1 - - libpng=1.6.37=h7cec526_2 - - libsodium=1.0.18=hbcb3906_1 - - libtiff=4.3.0=h1167814_1 - - libwebp-base=1.2.0=h0d85af4_2 - - llvm-openmp=12.0.1=hda6cdc1_1 - - lz4-c=1.9.3=h046ec9c_0 - - markupsafe=2.0.1=py37h271585c_0 - - matplotlib-base=3.4.2=py37hb018525_0 - - mistune=0.8.4=py37h271585c_1004 - - nbconvert=6.1.0=py37hf985489_0 - - ncurses=6.2=h2e338ed_4 - - numpy=1.21.1=py37h84c02c4_0 - - openjpeg=2.4.0=h6e7aa92_1 - - openssl=1.1.1k=h0d85af4_0 - - pandas=1.2.5=py37hb23ed4d_0 - - pandoc=2.14.1=h0d85af4_0 - - pillow=8.3.1=py37h76dc067_0 - - pyrsistent=0.17.3=py37h271585c_2 - - pysocks=1.7.1=py37hf985489_3 - - python=3.7.10=h7728216_100_cpython - - pyyaml=5.4.1=py37hf967b71_0 - - pyzmq=22.1.0=py37h8f778e5_0 - - readline=8.1=h05e3726_0 - - setuptools=49.6.0=py37hf985489_3 - - sqlite=3.36.0=h23a322b_0 - - terminado=0.10.1=py37hf985489_0 - - tk=8.6.10=h0419947_1 - - tornado=6.1=py37h271585c_1 - - xz=5.2.5=haf1e3a3_1 - - yaml=0.2.5=haf1e3a3_0 - - zeromq=4.3.4=h1c7c35f_0 - - zlib=1.2.11=h7795811_1010 - - zstd=1.5.0=h582d3a0_0 - win-64: - - brotlipy=0.7.0=py37hcc03f2d_1001 - - ca-certificates=2021.5.30=h5b45459_0 - - certifi=2021.5.30=py37h03978a9_0 - - cffi=1.14.6=py37hd8e9650_0 - - chardet=4.0.0=py37h03978a9_1 - - colorama=0.4.4=pyh9f0ad1d_0 - - cryptography=3.4.7=py37h20c650d_0 - - freetype=2.10.4=h546665d_1 - - importlib-metadata=4.6.1=py37h03978a9_0 - - intel-openmp=2021.3.0=h57928b3_3372 - - ipykernel=5.5.5=py37h7813e69_0 - - ipython=7.25.0=py37h7813e69_1 - - jbig=2.1=h8d14728_2003 - - jedi=0.18.0=py37h03978a9_2 - - jpeg=9d=h8ffe710_0 - - jupyter_core=4.7.1=py37h03978a9_0 - - kiwisolver=1.3.1=py37h8c56517_1 - - lcms2=2.12=h2a16943_0 - - lerc=2.2.1=h0e60522_0 - - libblas=3.9.0=10_mkl - - libcblas=3.9.0=10_mkl - - libdeflate=1.7=h8ffe710_5 - - liblapack=3.9.0=10_mkl - - libpng=1.6.37=h1d00b33_2 - - libsodium=1.0.18=h8d14728_1 - - libtiff=4.3.0=h0c97f57_1 - - lz4-c=1.9.3=h8ffe710_0 - - markupsafe=2.0.1=py37hcc03f2d_0 - - matplotlib-base=3.4.2=py37h0d1fb12_0 - - mistune=0.8.4=py37hcc03f2d_1004 - - mkl=2021.3.0=hb70f87d_564 - - nbconvert=6.1.0=py37h03978a9_0 - - numpy=1.21.1=py37hcbcd69c_0 - - openjpeg=2.4.0=hb211442_1 - - openssl=1.1.1k=h8ffe710_0 - - pandas=1.2.5=py37h90003fb_0 - - pandoc=2.14.1=h8ffe710_0 - - pillow=8.3.1=py37hd7d9ad0_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=1.1.3=py37h7f67f24_0 - - pyyaml=5.4.1=py37hcc03f2d_0 - - pyzmq=22.1.0=py37hcce574b_0 - - setuptools=49.6.0=py37h03978a9_3 - - sqlite=3.36.0=h8ffe710_0 - - tbb=2021.3.0=h2d74725_0 - - terminado=0.10.1=py37h03978a9_0 - - tk=8.6.10=h8ffe710_1 - - tornado=6.1=py37hcc03f2d_1 - - ucrt=10.0.20348.0=h57928b3_0 - - vc=14.2=hb210afc_5 - - vs2015_runtime=14.29.30037=h902a5da_5 - - 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 - - zlib=1.2.11=h62dcd97_1010 - - zstd=1.5.0=h6255e5f_0 default: locked: true - env_spec_hash: a8d706af59fa3a30148011cc332c2cc035881c84 + env_spec_hash: 9e8077cd3d1eff25e335cea353a80d59eb4da2a2 platforms: - linux-64 - osx-64 + - osx-arm64 - win-64 packages: all: - - altair=3.3.0=py37_0 - - async_generator=1.10=py_0 - - attrs=21.2.0=pyhd8ed1ab_0 - - backcall=0.2.0=pyh9f0ad1d_0 - - backports.functools_lru_cache=1.6.4=pyhd8ed1ab_0 - - backports=1.0=py_2 - - bleach=3.3.1=pyhd8ed1ab_0 - - bokeh=2.2.1=py37hc8dfbb8_1 - - charset-normalizer=2.0.0=pyhd8ed1ab_0 - - colorcet=2.0.6=pyhd8ed1ab_0 - - cycler=0.10.0=py_2 - - decorator=5.0.9=pyhd8ed1ab_0 - - defusedxml=0.7.1=pyhd8ed1ab_0 - - entrypoints=0.3=pyhd8ed1ab_1003 - - holoviews=1.14.1=pyhd3deb0d_0 - - hvplot=0.7.0=pyhd3deb0d_0 - - idna=3.1=pyhd3deb0d_0 - - ipython_genutils=0.2.0=py_1 - - jinja2=3.0.1=pyhd8ed1ab_0 - - jsonschema=3.2.0=pyhd8ed1ab_3 - - jupyter_client=6.1.12=pyhd8ed1ab_0 - - jupyterlab_pygments=0.1.2=pyh9f0ad1d_0 - - markdown=3.3.4=pyhd8ed1ab_0 - - matplotlib-inline=0.1.2=pyhd8ed1ab_2 - - nbclient=0.5.3=pyhd8ed1ab_0 - - nbformat=5.1.3=pyhd8ed1ab_0 - - nest-asyncio=1.5.1=pyhd8ed1ab_0 - - notebook=5.7.8=py37_1 - - olefile=0.46=pyh9f0ad1d_1 - - packaging=21.0=pyhd8ed1ab_0 - - pandocfilters=1.4.2=py_1 - - panel=0.10.2=pyhd8ed1ab_0 - - param=1.10.0=py_0 - - parso=0.8.2=pyhd8ed1ab_0 - - pickleshare=0.7.5=py_1003 - - pip=21.2.1=pyhd8ed1ab_0 - - plotly=5.1.0=pyhd8ed1ab_1 - - prometheus_client=0.11.0=pyhd8ed1ab_0 - - prompt-toolkit=3.0.19=pyha770c72_0 - - pycparser=2.20=pyh9f0ad1d_2 - - pyct-core=0.4.6=py_0 - - pyct=0.4.6=py_0 - - pygments=2.9.0=pyhd8ed1ab_0 - - pyopenssl=20.0.1=pyhd8ed1ab_0 - - pyparsing=2.4.7=pyh9f0ad1d_0 - - python-dateutil=2.8.2=pyhd8ed1ab_0 - - python_abi=3.7=2_cp37m - - pytz=2021.1=pyhd8ed1ab_0 - - pyviz_comms=2.1.0=pyhd8ed1ab_0 - - requests=2.26.0=pyhd8ed1ab_0 - - send2trash=1.7.1=pyhd8ed1ab_0 - - six=1.16.0=pyh6c4a22f_0 - - tenacity=8.0.1=pyhd8ed1ab_0 - - testpath=0.5.0=pyhd8ed1ab_0 - - toolz=0.11.1=py_0 - - tqdm=4.61.2=pyhd8ed1ab_1 - - traitlets=5.0.5=py_0 - - typing_extensions=3.10.0.0=pyha770c72_0 - - urllib3=1.26.6=pyhd8ed1ab_0 - - wcwidth=0.2.5=pyh9f0ad1d_2 - - webencodings=0.5.1=py_1 - - wheel=0.36.2=pyhd3deb0d_0 - - zipp=3.5.0=pyhd8ed1ab_0 + - 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 + - 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 + - ipython_genutils=0.2.0=pyhd3eb1b0_1 + - 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 + - pycparser=2.21=pyhd3eb1b0_0 + - python-dateutil=2.8.2=pyhd3eb1b0_0 + - python-tzdata=2023.3=pyhd3eb1b0_0 + - send2trash=1.8.0=pyhd3eb1b0_1 + - six=1.16.0=pyhd3eb1b0_1 + - stack_data=0.2.0=pyhd3eb1b0_0 + - tzdata=2023c=h04d1e81_0 + - wcwidth=0.2.5=pyhd3eb1b0_0 unix: - - libblas=3.9.0=10_openblas - - libcblas=3.9.0=10_openblas - - liblapack=3.9.0=10_openblas - - pexpect=4.8.0=pyh9f0ad1d_2 - - ptyprocess=0.7.0=pyhd3deb0d_0 + - pexpect=4.8.0=pyhd3eb1b0_3 + - ptyprocess=0.7.0=pyhd3eb1b0_2 linux-64: - - _libgcc_mutex=0.1=conda_forge - - _openmp_mutex=4.5=1_gnu - - brotlipy=0.7.0=py37h5e8e339_1001 - - ca-certificates=2021.5.30=ha878542_0 - - certifi=2021.5.30=py37h89c1867_0 - - cffi=1.14.6=py37hc58025e_0 - - chardet=4.0.0=py37h89c1867_1 - - cryptography=3.4.7=py37h5d9358c_0 - - freetype=2.10.4=h0708190_1 - - importlib-metadata=4.6.1=py37h89c1867_0 - - ipykernel=5.5.5=py37h085eea5_0 - - ipython=7.25.0=py37h085eea5_1 - - jbig=2.1=h7f98852_2003 - - jedi=0.18.0=py37h89c1867_2 - - jpeg=9d=h36c2ea0_0 - - jupyter_core=4.7.1=py37h89c1867_0 - - kiwisolver=1.3.1=py37h2527ec5_1 - - lcms2=2.12=hddcbb42_0 - - ld_impl_linux-64=2.36.1=hea4e1c9_2 - - lerc=2.2.1=h9c3ff4c_0 - - libdeflate=1.7=h7f98852_5 - - libffi=3.3=h58526e2_2 - - libgcc-ng=11.1.0=hc902ee8_4 - - libgfortran-ng=11.1.0=h69a702a_4 - - libgfortran5=11.1.0=h6c583b3_4 - - libgomp=11.1.0=hc902ee8_4 - - libopenblas=0.3.17=pthreads_h8fe5266_1 - - libpng=1.6.37=h21135ba_2 - - libsodium=1.0.18=h36c2ea0_1 - - libstdcxx-ng=11.1.0=h56837e0_4 - - libtiff=4.3.0=hf544144_1 - - libwebp-base=1.2.0=h7f98852_2 - - lz4-c=1.9.3=h9c3ff4c_0 - - markupsafe=2.0.1=py37h5e8e339_0 - - matplotlib-base=3.4.2=py37hdd32ed1_0 - - mistune=0.8.4=py37h5e8e339_1004 - - nbconvert=6.1.0=py37h89c1867_0 - - ncurses=6.2=h58526e2_4 - - numpy=1.21.1=py37h038b26d_0 - - openjpeg=2.4.0=hb52868f_1 - - openssl=1.1.1k=h7f98852_0 - - pandas=1.2.5=py37h219a48f_0 - - pandoc=2.14.1=h7f98852_0 - - pillow=8.3.1=py37h0f21c89_0 - - pyrsistent=0.17.3=py37h5e8e339_2 - - pysocks=1.7.1=py37h89c1867_3 - - python=3.7.10=hffdb5ce_100_cpython - - pyyaml=5.4.1=py37h5e8e339_0 - - pyzmq=22.1.0=py37h336d617_0 - - readline=8.1=h46c0cb4_0 - - setuptools=49.6.0=py37h89c1867_3 - - sqlite=3.36.0=h9cd32fc_0 - - terminado=0.10.1=py37h89c1867_0 - - tk=8.6.10=h21135ba_1 - - tornado=6.1=py37h5e8e339_1 - - xz=5.2.5=h516909a_1 - - yaml=0.2.5=h516909a_0 - - zeromq=4.3.4=h9c3ff4c_0 - - zlib=1.2.11=h516909a_1010 - - zstd=1.5.0=ha95c52a_0 + - _libgcc_mutex=0.1=main + - _openmp_mutex=5.1=1_gnu + - altair=5.0.1=py39h06a4308_0 + - anyio=3.5.0=py39h06a4308_0 + - argon2-cffi-bindings=21.2.0=py39h7f8727e_0 + - attrs=23.1.0=py39h06a4308_0 + - beautifulsoup4=4.12.2=py39h06a4308_0 + - blas=1.0=mkl + - bokeh=3.2.1=py39h2f386ee_0 + - 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 + - ca-certificates=2023.08.22=h06a4308_0 + - certifi=2023.7.22=py39h06a4308_0 + - cffi=1.15.1=py39h5eee18b_3 + - colorcet=3.0.1=py39h06a4308_0 + - comm=0.1.2=py39h06a4308_0 + - contourpy=1.0.5=py39hdb19cb5_0 + - cryptography=41.0.3=py39hdda0065_0 + - debugpy=1.6.7=py39h6a678d5_0 + - entrypoints=0.4=py39h06a4308_0 + - exceptiongroup=1.0.4=py39h06a4308_0 + - freetype=2.12.1=h4a9f257_0 + - giflib=5.2.1=h5eee18b_3 + - holoviews=1.17.1=py39h06a4308_0 + - hvplot=0.9.0=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 + - intel-openmp=2023.1.0=hdb19cb5_46305 + - 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=4.17.3=py39h06a4308_0 + - jupyter_client=7.4.9=py39h06a4308_0 + - jupyter_core=5.3.0=py39h06a4308_0 + - jupyter_server=1.23.4=py39h06a4308_0 + - kiwisolver=1.4.4=py39h6a678d5_0 + - lcms2=2.12=h3be6417_0 + - ld_impl_linux-64=2.38=h1181459_1 + - lerc=3.0=h295c915_0 + - libbrotlicommon=1.0.9=h5eee18b_7 + - libbrotlidec=1.0.9=h5eee18b_7 + - libbrotlienc=1.0.9=h5eee18b_7 + - libdeflate=1.17=h5eee18b_1 + - libffi=3.4.4=h6a678d5_0 + - libgcc-ng=11.2.0=h1234567_1 + - libgomp=11.2.0=h1234567_1 + - libpng=1.6.39=h5eee18b_0 + - libsodium=1.0.18=h7b6447c_0 + - libstdcxx-ng=11.2.0=h1234567_1 + - libtiff=4.5.1=h6a678d5_0 + - libwebp-base=1.3.2=h5eee18b_0 + - libwebp=1.3.2=h11a3e52_0 + - libxml2=2.10.4=hf1b16e4_1 + - libxslt=1.1.37=h5eee18b_1 + - linkify-it-py=2.0.0=py39h06a4308_0 + - lxml=4.9.3=py39hdbbb534_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=0.8.4=py39h27cfd23_1000 + - mkl-service=2.4.0=py39h5eee18b_1 + - mkl=2023.1.0=h213fc3f_46343 + - mkl_fft=1.3.8=py39h5eee18b_0 + - mkl_random=1.2.4=py39hdb19cb5_0 + - nbclassic=0.5.5=py39h06a4308_0 + - nbclient=0.5.13=py39h06a4308_0 + - nbconvert=6.5.4=py39h06a4308_0 + - nbformat=5.9.2=py39h06a4308_0 + - ncurses=6.4=h6a678d5_0 + - nest-asyncio=1.5.6=py39h06a4308_0 + - notebook-shim=0.2.2=py39h06a4308_0 + - notebook=6.5.4=py39h06a4308_1 + - numexpr=2.8.7=py39h85018f9_0 + - numpy-base=1.26.0=py39hb5e798b_0 + - numpy=1.26.0=py39h5f9d8c6_0 + - openjpeg=2.4.0=h3ad879b_0 + - openssl=3.0.11=h7f8727e_2 + - packaging=23.1=py39h06a4308_0 + - pandas=2.1.1=py39h1128e8f_0 + - panel=1.2.3=py39h06a4308_0 + - param=1.13.0=py39h06a4308_0 + - pillow=10.0.1=py39ha6cbd5a_0 + - pip=23.3=py39h06a4308_0 + - platformdirs=3.10.0=py39h06a4308_0 + - plotly=5.9.0=py39h06a4308_0 + - prometheus_client=0.14.1=py39h06a4308_0 + - prompt-toolkit=3.0.36=py39h06a4308_0 + - psutil=5.9.0=py39h5eee18b_0 + - pyct=0.5.0=py39h06a4308_0 + - pygments=2.15.1=py39h06a4308_1 + - pyopenssl=23.2.0=py39h06a4308_0 + - pyparsing=3.0.9=py39h06a4308_0 + - pyrsistent=0.18.0=py39heee7806_0 + - pysocks=1.7.1=py39h06a4308_0 + - python-fastjsonschema=2.16.2=py39h06a4308_0 + - python=3.9.18=h955ad1f_0 + - pytz=2023.3.post1=py39h06a4308_0 + - pyviz_comms=2.3.0=py39h06a4308_0 + - pyyaml=6.0.1=py39h5eee18b_0 + - pyzmq=23.2.0=py39h6a678d5_0 + - readline=8.2=h5eee18b_0 + - requests=2.31.0=py39h06a4308_0 + - setuptools=68.0.0=py39h06a4308_0 + - sniffio=1.2.0=py39h06a4308_1 + - soupsieve=2.5=py39h06a4308_0 + - sqlite=3.41.2=h5eee18b_0 + - tbb=2021.8.0=hdb19cb5_0 + - tenacity=8.2.2=py39h06a4308_0 + - terminado=0.17.1=py39h06a4308_0 + - tinycss2=1.2.1=py39h06a4308_0 + - tk=8.6.12=h1ccaba5_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 + - webencodings=0.5.1=py39h06a4308_1 + - websocket-client=0.58.0=py39h06a4308_4 + - wheel=0.41.2=py39h06a4308_0 + - xyzservices=2022.9.0=py39h06a4308_1 + - xz=5.4.2=h5eee18b_0 + - yaml=0.2.5=h7b6447c_0 + - zeromq=4.3.4=h2531618_0 + - zipp=3.11.0=py39h06a4308_0 + - zlib=1.2.13=h5eee18b_0 + - zstd=1.5.5=hc292b87_0 osx-64: - - appnope=0.1.2=py37hf985489_1 - - brotlipy=0.7.0=py37h271585c_1001 - - ca-certificates=2021.5.30=h033912b_0 - - certifi=2021.5.30=py37hf985489_0 - - cffi=1.14.6=py37hda351d9_0 - - chardet=4.0.0=py37hf985489_1 - - cryptography=3.4.7=py37hce4a858_0 - - freetype=2.10.4=h4cff582_1 - - importlib-metadata=4.6.1=py37hf985489_0 - - ipykernel=5.5.5=py37h85f7c60_0 - - ipython=7.25.0=py37h85f7c60_1 - - jbig=2.1=h0d85af4_2003 - - jedi=0.18.0=py37hf985489_2 - - jpeg=9d=hbcb3906_0 - - jupyter_core=4.7.1=py37hf985489_0 - - kiwisolver=1.3.1=py37h737db71_1 - - lcms2=2.12=h577c468_0 - - lerc=2.2.1=h046ec9c_0 - - libcxx=12.0.1=habf9029_0 - - libdeflate=1.7=h35c211d_5 - - libffi=3.3=h046ec9c_2 - - libgfortran5=9.3.0=h6c81a4c_23 - - libgfortran=5.0.0=9_3_0_h6c81a4c_23 - - libopenblas=0.3.17=openmp_h3351f45_1 - - libpng=1.6.37=h7cec526_2 - - libsodium=1.0.18=hbcb3906_1 - - libtiff=4.3.0=h1167814_1 - - libwebp-base=1.2.0=h0d85af4_2 - - llvm-openmp=12.0.1=hda6cdc1_1 - - lz4-c=1.9.3=h046ec9c_0 - - markupsafe=2.0.1=py37h271585c_0 - - matplotlib-base=3.4.2=py37hb018525_0 - - mistune=0.8.4=py37h271585c_1004 - - nbconvert=6.1.0=py37hf985489_0 - - ncurses=6.2=h2e338ed_4 - - numpy=1.21.1=py37h84c02c4_0 - - openjpeg=2.4.0=h6e7aa92_1 - - openssl=1.1.1k=h0d85af4_0 - - pandas=1.2.5=py37hb23ed4d_0 - - pandoc=2.14.1=h0d85af4_0 - - pillow=8.3.1=py37h76dc067_0 - - pyrsistent=0.17.3=py37h271585c_2 - - pysocks=1.7.1=py37hf985489_3 - - python=3.7.10=h7728216_100_cpython - - pyyaml=5.4.1=py37hf967b71_0 - - pyzmq=22.1.0=py37h8f778e5_0 - - readline=8.1=h05e3726_0 - - setuptools=49.6.0=py37hf985489_3 - - sqlite=3.36.0=h23a322b_0 - - terminado=0.10.1=py37hf985489_0 - - tk=8.6.10=h0419947_1 - - tornado=6.1=py37h271585c_1 - - xz=5.2.5=haf1e3a3_1 + - altair=5.0.1=py39hecd8cb5_0 + - anyio=3.5.0=py39hecd8cb5_0 + - appnope=0.1.2=py39hecd8cb5_1001 + - argon2-cffi-bindings=21.2.0=py39hca72f7f_0 + - attrs=23.1.0=py39hecd8cb5_0 + - beautifulsoup4=4.12.2=py39hecd8cb5_0 + - blas=1.0=mkl + - bokeh=3.2.1=py39h20db666_0 + - 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 + - ca-certificates=2023.08.22=hecd8cb5_0 + - certifi=2023.7.22=py39hecd8cb5_0 + - cffi=1.15.1=py39h6c40b1e_3 + - colorcet=3.0.1=py39hecd8cb5_0 + - comm=0.1.2=py39hecd8cb5_0 + - contourpy=1.0.5=py39haf03e11_0 + - cryptography=41.0.3=py39h30e54ef_0 + - debugpy=1.6.7=py39hcec6c5f_0 + - entrypoints=0.4=py39hecd8cb5_0 + - exceptiongroup=1.0.4=py39hecd8cb5_0 + - freetype=2.12.1=hd8bbffd_0 + - giflib=5.2.1=h6c40b1e_3 + - holoviews=1.17.1=py39hecd8cb5_0 + - hvplot=0.9.0=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 + - intel-openmp=2023.1.0=ha357a0b_43547 + - 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=4.17.3=py39hecd8cb5_0 + - jupyter_client=7.4.9=py39hecd8cb5_0 + - jupyter_core=5.3.0=py39hecd8cb5_0 + - jupyter_server=1.23.4=py39hecd8cb5_0 + - kiwisolver=1.4.4=py39hcec6c5f_0 + - lcms2=2.12=hf1fd2bf_0 + - lerc=3.0=he9d5cce_0 + - libbrotlicommon=1.0.9=hca72f7f_7 + - libbrotlidec=1.0.9=hca72f7f_7 + - libbrotlienc=1.0.9=hca72f7f_7 + - libcxx=14.0.6=h9765a3e_0 + - libdeflate=1.17=hb664fd8_1 + - libffi=3.4.4=hecd8cb5_0 + - libiconv=1.16=hca72f7f_2 + - libpng=1.6.39=h6c40b1e_0 + - libsodium=1.0.18=h1de35cc_0 + - libtiff=4.5.1=hcec6c5f_0 + - libwebp-base=1.3.2=h6c40b1e_0 + - libwebp=1.3.2=hf6ce154_0 + - libxml2=2.10.4=h1bd7e62_1 + - libxslt=1.1.37=h6c40b1e_1 + - linkify-it-py=2.0.0=py39hecd8cb5_0 + - lxml=4.9.3=py39h946e0e5_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=0.8.4=py39h9ed2024_1000 + - mkl-service=2.4.0=py39h6c40b1e_1 + - mkl=2023.1.0=h8e150cf_43559 + - mkl_fft=1.3.8=py39h6c40b1e_0 + - mkl_random=1.2.4=py39ha357a0b_0 + - nbclassic=0.5.5=py39hecd8cb5_0 + - nbclient=0.5.13=py39hecd8cb5_0 + - nbconvert=6.5.4=py39hecd8cb5_0 + - nbformat=5.9.2=py39hecd8cb5_0 + - ncurses=6.4=hcec6c5f_0 + - nest-asyncio=1.5.6=py39hecd8cb5_0 + - notebook-shim=0.2.2=py39hecd8cb5_0 + - notebook=6.5.4=py39hecd8cb5_1 + - numexpr=2.8.7=py39h827a554_0 + - numpy-base=1.26.0=py39ha186be2_0 + - numpy=1.26.0=py39h827a554_0 + - openjpeg=2.4.0=h66ea3da_0 + - openssl=3.0.11=hca72f7f_2 + - packaging=23.1=py39hecd8cb5_0 + - pandas=2.1.1=py39h3ea8b11_0 + - panel=1.2.3=py39hecd8cb5_0 + - param=1.13.0=py39hecd8cb5_0 + - pillow=10.0.1=py39h7d39338_0 + - pip=23.3=py39hecd8cb5_0 + - platformdirs=3.10.0=py39hecd8cb5_0 + - plotly=5.9.0=py39hecd8cb5_0 + - prometheus_client=0.14.1=py39hecd8cb5_0 + - prompt-toolkit=3.0.36=py39hecd8cb5_0 + - psutil=5.9.0=py39hca72f7f_0 + - pyct=0.5.0=py39hecd8cb5_0 + - pygments=2.15.1=py39hecd8cb5_1 + - pyopenssl=23.2.0=py39hecd8cb5_0 + - pyparsing=3.0.9=py39hecd8cb5_0 + - pyrsistent=0.18.0=py39hca72f7f_0 + - pysocks=1.7.1=py39hecd8cb5_0 + - python-fastjsonschema=2.16.2=py39hecd8cb5_0 + - python=3.9.18=h5ee71fb_0 + - pytz=2023.3.post1=py39hecd8cb5_0 + - pyviz_comms=2.3.0=py39hecd8cb5_0 + - pyyaml=6.0.1=py39h6c40b1e_0 + - pyzmq=23.2.0=py39he9d5cce_0 + - readline=8.2=hca72f7f_0 + - requests=2.31.0=py39hecd8cb5_0 + - setuptools=68.0.0=py39hecd8cb5_0 + - sniffio=1.2.0=py39hecd8cb5_1 + - soupsieve=2.5=py39hecd8cb5_0 + - sqlite=3.41.2=h6c40b1e_0 + - tbb=2021.8.0=ha357a0b_0 + - tenacity=8.2.2=py39hecd8cb5_0 + - terminado=0.17.1=py39hecd8cb5_0 + - tinycss2=1.2.1=py39hecd8cb5_0 + - tk=8.6.12=h5d9f67b_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 + - webencodings=0.5.1=py39hecd8cb5_1 + - websocket-client=0.58.0=py39hecd8cb5_4 + - wheel=0.41.2=py39hecd8cb5_0 + - xyzservices=2022.9.0=py39hecd8cb5_1 + - xz=5.4.2=h6c40b1e_0 - yaml=0.2.5=haf1e3a3_0 - - zeromq=4.3.4=h1c7c35f_0 - - zlib=1.2.11=h7795811_1010 - - zstd=1.5.0=h582d3a0_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: + - altair=5.0.1=py39hca03da5_0 + - anyio=3.5.0=py39hca03da5_0 + - appnope=0.1.2=py39hca03da5_1001 + - argon2-cffi-bindings=21.2.0=py39h1a28f6b_0 + - attrs=23.1.0=py39hca03da5_0 + - beautifulsoup4=4.12.2=py39hca03da5_0 + - blas=1.0=openblas + - bokeh=3.2.1=py39h33ce5c2_0 + - 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 + - ca-certificates=2023.08.22=hca03da5_0 + - certifi=2023.7.22=py39hca03da5_0 + - cffi=1.15.1=py39h80987f9_3 + - colorcet=3.0.1=py39hca03da5_0 + - comm=0.1.2=py39hca03da5_0 + - contourpy=1.0.5=py39h525c30c_0 + - cryptography=41.0.3=py39hd4332d6_0 + - debugpy=1.6.7=py39h313beb8_0 + - entrypoints=0.4=py39hca03da5_0 + - exceptiongroup=1.0.4=py39hca03da5_0 + - freetype=2.12.1=h1192e45_0 + - giflib=5.2.1=h80987f9_3 + - holoviews=1.17.1=py39hca03da5_0 + - hvplot=0.9.0=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=4.17.3=py39hca03da5_0 + - jupyter_client=7.4.9=py39hca03da5_0 + - jupyter_core=5.3.0=py39hca03da5_0 + - jupyter_server=1.23.4=py39hca03da5_0 + - kiwisolver=1.4.4=py39h313beb8_0 + - lcms2=2.12=hba8e193_0 + - lerc=3.0=hc377ac9_0 + - libbrotlicommon=1.0.9=h1a28f6b_7 + - libbrotlidec=1.0.9=h1a28f6b_7 + - libbrotlienc=1.0.9=h1a28f6b_7 + - libcxx=14.0.6=h848a8c0_0 + - libdeflate=1.17=h80987f9_1 + - libffi=3.4.4=hca03da5_0 + - libgfortran5=11.3.0=h009349e_28 + - libgfortran=5.0.0=11_3_0_hca03da5_28 + - libiconv=1.16=h1a28f6b_2 + - libopenblas=0.3.21=h269037a_0 + - libpng=1.6.39=h80987f9_0 + - libsodium=1.0.18=h1a28f6b_0 + - libtiff=4.5.1=h313beb8_0 + - libwebp-base=1.3.2=h80987f9_0 + - libwebp=1.3.2=ha3663a8_0 + - libxml2=2.10.4=h0dcf63f_1 + - libxslt=1.1.37=h80987f9_1 + - linkify-it-py=2.0.0=py39hca03da5_0 + - llvm-openmp=14.0.6=hc6e5704_0 + - lxml=4.9.3=py39h50ffb84_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=0.8.4=py39h1a28f6b_1000 + - nbclassic=0.5.5=py39hca03da5_0 + - nbclient=0.5.13=py39hca03da5_0 + - nbconvert=6.5.4=py39hca03da5_0 + - nbformat=5.9.2=py39hca03da5_0 + - ncurses=6.4=h313beb8_0 + - nest-asyncio=1.5.6=py39hca03da5_0 + - notebook-shim=0.2.2=py39hca03da5_0 + - notebook=6.5.4=py39hca03da5_1 + - numexpr=2.8.7=py39hecc3335_0 + - numpy-base=1.26.0=py39ha9811e2_0 + - numpy=1.26.0=py39h3b2db8e_0 + - openjpeg=2.3.0=h7a6adac_2 + - openssl=3.0.11=h1a28f6b_2 + - packaging=23.1=py39hca03da5_0 + - pandas=2.1.1=py39h46d7db6_0 + - panel=1.2.3=py39hca03da5_0 + - param=1.13.0=py39hca03da5_0 + - pillow=10.0.1=py39h3b245a6_0 + - pip=23.3=py39hca03da5_0 + - platformdirs=3.10.0=py39hca03da5_0 + - plotly=5.9.0=py39hca03da5_0 + - prometheus_client=0.14.1=py39hca03da5_0 + - prompt-toolkit=3.0.36=py39hca03da5_0 + - psutil=5.9.0=py39h1a28f6b_0 + - pyct=0.5.0=py39hca03da5_0 + - pygments=2.15.1=py39hca03da5_1 + - pyopenssl=23.2.0=py39hca03da5_0 + - pyparsing=3.0.9=py39hca03da5_0 + - pyrsistent=0.18.0=py39h1a28f6b_0 + - pysocks=1.7.1=py39hca03da5_0 + - python-fastjsonschema=2.16.2=py39hca03da5_0 + - python=3.9.18=hb885b13_0 + - pytz=2023.3.post1=py39hca03da5_0 + - pyviz_comms=2.3.0=py39hca03da5_0 + - pyyaml=6.0.1=py39h80987f9_0 + - pyzmq=23.2.0=py39hc377ac9_0 + - readline=8.2=h1a28f6b_0 + - requests=2.31.0=py39hca03da5_0 + - setuptools=68.0.0=py39hca03da5_0 + - sniffio=1.2.0=py39hca03da5_1 + - soupsieve=2.5=py39hca03da5_0 + - sqlite=3.41.2=h80987f9_0 + - tenacity=8.2.2=py39hca03da5_0 + - terminado=0.17.1=py39hca03da5_0 + - tinycss2=1.2.1=py39hca03da5_0 + - tk=8.6.12=hb8d0fd4_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 + - webencodings=0.5.1=py39hca03da5_1 + - websocket-client=0.58.0=py39hca03da5_4 + - wheel=0.41.2=py39hca03da5_0 + - xyzservices=2022.9.0=py39hca03da5_1 + - xz=5.4.2=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: - - brotlipy=0.7.0=py37hcc03f2d_1001 - - ca-certificates=2021.5.30=h5b45459_0 - - certifi=2021.5.30=py37h03978a9_0 - - cffi=1.14.6=py37hd8e9650_0 - - chardet=4.0.0=py37h03978a9_1 - - colorama=0.4.4=pyh9f0ad1d_0 - - cryptography=3.4.7=py37h20c650d_0 - - freetype=2.10.4=h546665d_1 - - importlib-metadata=4.6.1=py37h03978a9_0 - - intel-openmp=2021.3.0=h57928b3_3372 - - ipykernel=5.5.5=py37h7813e69_0 - - ipython=7.25.0=py37h7813e69_1 - - jbig=2.1=h8d14728_2003 - - jedi=0.18.0=py37h03978a9_2 - - jpeg=9d=h8ffe710_0 - - jupyter_core=4.7.1=py37h03978a9_0 - - kiwisolver=1.3.1=py37h8c56517_1 - - lcms2=2.12=h2a16943_0 - - lerc=2.2.1=h0e60522_0 - - libblas=3.9.0=10_mkl - - libcblas=3.9.0=10_mkl - - libdeflate=1.7=h8ffe710_5 - - liblapack=3.9.0=10_mkl - - libpng=1.6.37=h1d00b33_2 - - libsodium=1.0.18=h8d14728_1 - - libtiff=4.3.0=h0c97f57_1 - - lz4-c=1.9.3=h8ffe710_0 - - markupsafe=2.0.1=py37hcc03f2d_0 - - matplotlib-base=3.4.2=py37h0d1fb12_0 - - mistune=0.8.4=py37hcc03f2d_1004 - - mkl=2021.3.0=hb70f87d_564 - - nbconvert=6.1.0=py37h03978a9_0 - - numpy=1.21.1=py37hcbcd69c_0 - - openjpeg=2.4.0=hb211442_1 - - openssl=1.1.1k=h8ffe710_0 - - pandas=1.2.5=py37h90003fb_0 - - pandoc=2.14.1=h8ffe710_0 - - pillow=8.3.1=py37hd7d9ad0_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=1.1.3=py37h7f67f24_0 - - pyyaml=5.4.1=py37hcc03f2d_0 - - pyzmq=22.1.0=py37hcce574b_0 - - setuptools=49.6.0=py37h03978a9_3 - - sqlite=3.36.0=h8ffe710_0 - - tbb=2021.3.0=h2d74725_0 - - terminado=0.10.1=py37h03978a9_0 - - tk=8.6.10=h8ffe710_1 - - tornado=6.1=py37hcc03f2d_1 - - ucrt=10.0.20348.0=h57928b3_0 - - vc=14.2=hb210afc_5 - - vs2015_runtime=14.29.30037=h902a5da_5 - - win_inet_pton=1.1.0=py37h03978a9_2 - - wincertstore=0.2=py37h03978a9_1006 + - altair=5.0.1=py39haa95532_0 + - anyio=3.5.0=py39haa95532_0 + - argon2-cffi-bindings=21.2.0=py39h2bbff1b_0 + - attrs=23.1.0=py39haa95532_0 + - beautifulsoup4=4.12.2=py39haa95532_0 + - blas=1.0=mkl + - bokeh=3.2.1=py39h9909e9c_0 + - 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 + - ca-certificates=2023.08.22=haa95532_0 + - certifi=2023.7.22=py39haa95532_0 + - cffi=1.15.1=py39h2bbff1b_3 + - colorama=0.4.6=py39haa95532_0 + - colorcet=3.0.1=py39haa95532_0 + - comm=0.1.2=py39haa95532_0 + - contourpy=1.0.5=py39h59b6b97_0 + - cryptography=41.0.3=py39h89fc84f_0 + - debugpy=1.6.7=py39hd77b12b_0 + - entrypoints=0.4=py39haa95532_0 + - exceptiongroup=1.0.4=py39haa95532_0 + - freetype=2.12.1=ha860e81_0 + - giflib=5.2.1=h8cc25b3_3 + - holoviews=1.17.1=py39haa95532_0 + - hvplot=0.9.0=py39haa95532_0 + - 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_46319 + - 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=4.17.3=py39haa95532_0 + - jupyter_client=7.4.9=py39haa95532_0 + - jupyter_core=5.3.0=py39haa95532_0 + - jupyter_server=1.23.4=py39haa95532_0 + - kiwisolver=1.4.4=py39hd77b12b_0 + - lerc=3.0=hd77b12b_0 + - libbrotlicommon=1.0.9=h2bbff1b_7 + - libbrotlidec=1.0.9=h2bbff1b_7 + - libbrotlienc=1.0.9=h2bbff1b_7 + - libdeflate=1.17=h2bbff1b_1 + - libiconv=1.16=h2bbff1b_2 + - libpng=1.6.39=h8cc25b3_0 + - libsodium=1.0.18=h62dcd97_0 + - libtiff=4.5.1=hd77b12b_0 + - libwebp-base=1.3.2=h2bbff1b_0 + - libwebp=1.3.2=hbc33d0d_0 + - libxml2=2.10.4=h0ad7f3c_1 + - libxslt=1.1.37=h2bbff1b_1 + - linkify-it-py=2.0.0=py39haa95532_0 + - lxml=4.9.3=py39h09808a7_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=0.8.4=py39h2bbff1b_1000 + - mkl-service=2.4.0=py39h2bbff1b_1 + - mkl=2023.1.0=h6b88ed4_46357 + - mkl_fft=1.3.8=py39h2bbff1b_0 + - mkl_random=1.2.4=py39h59b6b97_0 + - nbclassic=0.5.5=py39haa95532_0 + - nbclient=0.5.13=py39haa95532_0 + - nbconvert=6.5.4=py39haa95532_0 + - nbformat=5.9.2=py39haa95532_0 + - nest-asyncio=1.5.6=py39haa95532_0 + - notebook-shim=0.2.2=py39haa95532_0 + - notebook=6.5.4=py39haa95532_1 + - numexpr=2.8.7=py39h2cd9be0_0 + - numpy-base=1.26.0=py39h65a83cf_0 + - numpy=1.26.0=py39h055cbcc_0 + - openjpeg=2.4.0=h4fc8c34_0 + - openssl=3.0.11=h2bbff1b_2 + - packaging=23.1=py39haa95532_0 + - pandas=2.1.1=py39h4ed8f06_0 + - panel=1.2.3=py39haa95532_0 + - param=1.13.0=py39haa95532_0 + - pillow=10.0.1=py39h045eedc_0 + - pip=23.3=py39haa95532_0 + - platformdirs=3.10.0=py39haa95532_0 + - plotly=5.9.0=py39haa95532_0 + - prometheus_client=0.14.1=py39haa95532_0 + - prompt-toolkit=3.0.36=py39haa95532_0 + - psutil=5.9.0=py39h2bbff1b_0 + - pyct=0.5.0=py39haa95532_0 + - pygments=2.15.1=py39haa95532_1 + - pyopenssl=23.2.0=py39haa95532_0 + - pyparsing=3.0.9=py39haa95532_0 + - pyrsistent=0.18.0=py39h196d8e1_0 + - pysocks=1.7.1=py39haa95532_0 + - python-fastjsonschema=2.16.2=py39haa95532_0 + - python=3.9.18=h1aa4202_0 + - pytz=2023.3.post1=py39haa95532_0 + - pyviz_comms=2.3.0=py39haa95532_0 + - pywin32=305=py39h2bbff1b_0 + - pywinpty=2.0.10=py39h5da7b33_0 + - pyyaml=6.0.1=py39h2bbff1b_0 + - pyzmq=23.2.0=py39hd77b12b_0 + - requests=2.31.0=py39haa95532_0 + - setuptools=68.0.0=py39haa95532_0 + - sniffio=1.2.0=py39haa95532_1 + - soupsieve=2.5=py39haa95532_0 + - sqlite=3.41.2=h2bbff1b_0 + - tbb=2021.8.0=h59b6b97_0 + - tenacity=8.2.2=py39haa95532_0 + - terminado=0.17.1=py39haa95532_0 + - tinycss2=1.2.1=py39haa95532_0 + - tk=8.6.12=h2bbff1b_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 + - 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 - - xz=5.2.5=h62dcd97_1 + - xyzservices=2022.9.0=py39haa95532_1 + - xz=5.4.2=h8cc25b3_0 - yaml=0.2.5=he774522_0 - - zeromq=4.3.4=h0e60522_0 - - zlib=1.2.11=h62dcd97_1010 - - zstd=1.5.0=h6255e5f_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/gapminders/anaconda-project.yml b/gapminders/anaconda-project.yml index e7c00e4ae..606198ba2 100644 --- a/gapminders/anaconda-project.yml +++ b/gapminders/anaconda-project.yml @@ -3,59 +3,46 @@ name: gapminders description: Using four different plotting libraries for the Hans Rosling gapminder example examples_config: + created: 2018-01-01 maintainers: - philippjfr labels: - panel - - channel_conda-forge + deployments: + - command: dashboard + no_data_ingestion: true user_fields: [examples_config] channels: -- conda-forge -- defaults # Previously nodefaults attempt +- defaults packages: &pkgs -- python=3.7 -- notebook=5.7.8 +- python=3.9 +- notebook - plotly -- holoviews=1.14.1 -- hvplot=0.7.0 -- panel=0.10.2 -- param=1.10.0 -- bokeh=2.2.1 -- altair=3 -- pandas = 1.2.5 +- holoviews +- hvplot +- panel >=1 +- param +- bokeh >=3 +- altair +- pandas dependencies: *pkgs commands: dashboard: - unix: panel serve gapminders.ipynb --show + unix: panel serve --rest-session-info --session-history -1 gapminders.ipynb --show supports_http_options: true notebook: notebook: gapminders.ipynb - test: - unix: pytest --nbsmoke-run -k *.ipynb --ignore envs - windows: pytest --nbsmoke-run -k *.ipynb --ignore envs - env_spec: test - lint: - unix: pytest --nbsmoke-lint -k *.ipynb --ignore envs - windows: pytest --nbsmoke-lint -k *.ipynb --ignore envs - env_spec: test variables: {} downloads: {} -env_specs: - default: {} - test: - packages: &testpkgs - - nbsmoke=0.2.8 - - pytest=4.4.1 - dependencies: *testpkgs - platforms: - linux-64 - osx-64 - win-64 +- osx-arm64 diff --git a/gapminders/assets/app.jpg b/gapminders/assets/app.jpg new file mode 100644 index 000000000..8590689fd Binary files /dev/null and b/gapminders/assets/app.jpg differ diff --git a/gapminders/gapminders.ipynb b/gapminders/gapminders.ipynb index 85a706cb2..31e25bcde 100644 --- a/gapminders/gapminders.ipynb +++ b/gapminders/gapminders.ipynb @@ -4,24 +4,23 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Gapminders\n", - "Written by Philipp Rudiger
\n", - "Created: 2018
\n", - "Last updated: January 14, 2021" + "# Gapminders" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "" + "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The [Panel](http://panel.holoviz.org) library from [HoloViz](http://holoviz.org) lets you make widget-controlled apps and dashboards from a wide variety of [plotting libraries and data types](https://github.com/holoviz/panel/issues/2). Here let's set up four different plotting libraries controlled by a couple of widgets, for Hans Rosling's [gapminder](https://www.gapminder.org/tag/hans-rosling/) example." + "The [Panel](https://panel.holoviz.org) library from [HoloViz](https://holoviz.org) lets you make widget-controlled apps and dashboards from a wide variety of [plotting libraries and data types](https://panel.holoviz.org/reference/index.html#panes). \n", + "\n", + "**Here we set up four different plotting libraries controlled by a couple of widgets, for Hans Rosling's [gapminder](https://demo.bokeh.org/gapminder) example.**" ] }, { @@ -30,30 +29,93 @@ "metadata": {}, "outputs": [], "source": [ - "import param\n", + "import warnings\n", + "\n", "import numpy as np \n", "import pandas as pd\n", "import panel as pn\n", - "import holoviews as hv\n", "\n", "import altair as alt\n", "import plotly.graph_objs as go\n", + "import plotly.io as pio\n", "import matplotlib.pyplot as plt\n", + "import hvplot.pandas # noqa\n", "\n", - "pn.extension('vega', 'plotly')\n", + "warnings.simplefilter('ignore')\n", + "pn.extension('vega', 'plotly', defer_load=True, sizing_mode=\"stretch_width\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need to define some configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "XLABEL = 'GDP per capita (2000 dollars)'\n", + "YLABEL = 'Life expectancy (years)'\n", + "YLIM = (20, 90)\n", + "HEIGHT=500 # pixels\n", + "WIDTH=500 # pixels\n", + "ACCENT=\"#00A170\"\n", "\n", - "import hvplot.pandas # noqa: adds hvplot to pandas objects as a side effect\n", + "PERIOD = 1000 # miliseconds" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Extract the dataset\n", "\n", - "# Disable default plotly theme\n", - "import plotly.io as pio\n", - "pio.templates.default = None" + "First, we'll get the data into a Pandas dataframe. We use the [built in `cache`](https://panel.holoviz.org/user_guide/Performance_and_Debugging.html#caching) to speed up the app." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@pn.cache\n", + "def get_dataset():\n", + " url = 'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'\n", + " return pd.read_csv(url)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "dataset = get_dataset()\n", + "dataset.sample(10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "YEARS = [int(year) for year in dataset.year.unique()]\n", + "YEARS" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "First, we'll get the data into a Pandas dataframe:" + "## Transform the dataset to plots\n", + "\n", + "Now let's define helper functions and functions to plot this dataset with Matplotlib, Plotly, Altair, and hvPlot (using HoloViews and Bokeh)." ] }, { @@ -62,15 +124,25 @@ "metadata": {}, "outputs": [], "source": [ - "url = 'https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv'\n", - "dataset = pd.read_csv(url)" + "@pn.cache\n", + "def get_data(year):\n", + " df = dataset[(dataset.year==year) & (dataset.gdpPercap < 10000)].copy()\n", + " df['size'] = np.sqrt(df['pop']*2.666051223553066e-05)\n", + " df['size_hvplot'] = df['size']*6\n", + " return df\n", + "\n", + "def get_title(library, year):\n", + " return f\"{library}: Life expectancy vs. GDP, {year}\"\n", + "\n", + "def get_xlim(data):\n", + " return (data['gdpPercap'].min()-100,data['gdpPercap'].max()+1000)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now let's define a couple of user-settable parameters (the year and whether to show a legend), then write methods to plot this data with Matplotlib, Plotly, Altair (using Vega), and hvPlot (using HoloViews and Bokeh):" + "Let's define the **Matplotlib** plotting function." ] }, { @@ -79,93 +151,44 @@ "metadata": {}, "outputs": [], "source": [ - "class Gapminder(param.Parameterized):\n", - " year = param.ObjectSelector(default=1952, objects=list(dataset.year.unique()))\n", - " show_legend = param.Boolean(default=True)\n", - " \n", - " title = 'Life expectancy vs. GDP, %s'\n", - " xlabel = 'GDP per capita (2000 dollars)'\n", - " ylabel = 'Life expectancy (years)'\n", - " ylim = (20, 90)\n", - " xlim = (200, 15000)\n", + "plt.rcParams.update({\n", + " \"savefig.facecolor\": (0.0, 0.0, 0.0, 0.0), \n", + "})\n", "\n", - " def get_data(self):\n", - " df = dataset[(dataset.year==self.year) & (dataset.gdpPercap < 10000)].copy()\n", - " df['size'] = np.sqrt(df['pop']*2.666051223553066e-05)\n", - " return df\n", - " \n", - " def mpl_view(self):\n", - " data = self.get_data()\n", - " title = \"Matplotlib: \" + (self.title % self.year)\n", - " \n", - " plot = plt.figure(figsize=(7, 6))\n", - " ax = plot.add_subplot(111)\n", - " ax.set_xscale(\"log\", nonpositive='clip')\n", - " ax.set_title(title)\n", - " ax.set_xlabel(self.xlabel)\n", - " ax.set_ylabel(self.ylabel)\n", - " ax.set_ylim(self.ylim)\n", - " ax.set_xlim(self.xlim)\n", "\n", - " for continent, df in data.groupby('continent'):\n", - " ax.scatter(df.gdpPercap, y=df.lifeExp, s=df['size']*5,\n", - " edgecolor='black', label=continent)\n", - " \n", - " if self.show_legend:\n", - " ax.legend(loc=4)\n", - " \n", - " plt.close(plot)\n", - " return plot\n", - " \n", - " def plotly_view(self):\n", - " data = self.get_data()\n", - " title = 'Plotly: ' + (self.title % self.year)\n", + "@pn.cache\n", + "def mpl_view(year=1952, show_legend=True):\n", + " data = get_data(year)\n", + " title = get_title(\"Matplotlib\", year)\n", + " xlim = get_xlim(data)\n", "\n", - " traces = []\n", - " for continent, df in data.groupby('continent'):\n", - " marker=dict(symbol='circle', sizemode='area', sizeref=0.1, size=df['size'], line=dict(width=2))\n", - " traces.append(go.Scatter(x=df.gdpPercap, y=df.lifeExp, mode='markers', marker=marker, name=continent))\n", - " \n", - " axis_opts = dict(gridcolor='rgb(255, 255, 255)', zerolinewidth=1, ticklen=5, gridwidth=2)\n", - " layout = go.Layout(title=title, showlegend=self.show_legend, width=550,\n", - " xaxis=dict(title=self.xlabel, type='log', **axis_opts),\n", - " yaxis=dict( title=self.ylabel, **axis_opts))\n", - " \n", - " return go.Figure(data=traces, layout=layout)\n", - " \n", - " def altair_view(self):\n", - " data = self.get_data()\n", - " title = \"Altair/Vega: \" + (self.title % self.year)\n", - " legend= ({} if self.show_legend else {'legend': None})\n", + " plot = plt.figure(figsize=(10, 6), facecolor=(0, 0, 0, 0))\n", + " ax = plot.add_subplot(111)\n", + " ax.set_xscale(\"log\")\n", + " ax.set_title(title)\n", + " ax.set_xlabel(XLABEL)\n", + " ax.set_ylabel(YLABEL)\n", + " ax.set_ylim(YLIM)\n", + " ax.set_xlim(xlim)\n", "\n", - " plot = alt.Chart(data).mark_circle().encode(\n", - " alt.X('gdpPercap:Q', scale=alt.Scale(type='log'), axis=alt.Axis(title=self.xlabel)),\n", - " alt.Y('lifeExp:Q', scale=alt.Scale(zero=False, domain=self.ylim), axis=alt.Axis(title=self.ylabel)),\n", - " size=alt.Size('pop:Q', scale=alt.Scale(type=\"log\"), legend=None),\n", - " color=alt.Color('continent', scale=alt.Scale(scheme=\"category10\"), **legend))\\\n", - " .properties(title=title).configure_axis(grid=False)\n", - " return plot\n", - " \n", - " def hvplot_view(self):\n", - " data = self.get_data()\n", - " title = \"hvPlot/Bokeh: \" + (self.title % self.year)\n", - " \n", - " legend = 'bottom_right' if self.show_legend else None\n", - " return data.hvplot.scatter(\n", - " 'gdpPercap', 'lifeExp', by='continent', size=np.sqrt(hv.dim('size'))*3, line_color='black',\n", - " logx=True, title=title, width=500, height=400, legend=legend,\n", - " xlabel=self.xlabel, ylabel=self.ylabel, xticks=[500, 1000, 2000, 5000, 10000],\n", - " ylim=self.ylim, xlim=(200, 12000)\n", - " )\n", + " for continent, df in data.groupby('continent'):\n", + " ax.scatter(df.gdpPercap, y=df.lifeExp, s=df['size']*5,\n", + " edgecolor='black', label=continent)\n", + "\n", + " if show_legend:\n", + " ax.legend(loc=4)\n", + "\n", + " plt.close(plot)\n", + " return plot\n", "\n", - "gm = Gapminder(name='')" + "mpl_view(1952, True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We can now make a panel showing the parameters of this `gm` object along with the result of calling four different `_view()` methods:" + "Let's define the **Plotly** plotting function." ] }, { @@ -174,20 +197,36 @@ "metadata": {}, "outputs": [], "source": [ - "pn.Column(\n", - " gm.param,\n", - " pn.Row(gm.hvplot_view, gm.altair_view),\n", - " pn.Row(gm.mpl_view, gm.plotly_view)\n", - ")" + "pio.templates.default = None\n", + "\n", + "@pn.cache\n", + "def plotly_view(year=1952, show_legend=True):\n", + " data = get_data(year)\n", + " title = get_title(\"Plotly\", year)\n", + "\n", + " traces = []\n", + " for continent, df in data.groupby('continent'):\n", + " marker=dict(symbol='circle', sizemode='area', sizeref=0.1, size=df['size'], line=dict(width=2))\n", + " traces.append(go.Scatter(x=df.gdpPercap, y=df.lifeExp, mode='markers', marker=marker, name=continent, text=df.country))\n", + "\n", + " axis_opts = dict(gridcolor='rgb(255, 255, 255)', zerolinewidth=1, ticklen=5, gridwidth=2)\n", + " layout = go.Layout(\n", + " title=title, showlegend=show_legend,\n", + " xaxis=dict(title=XLABEL, type='log', **axis_opts),\n", + " yaxis=dict(title=YLABEL, **axis_opts),\n", + " autosize=True, paper_bgcolor='rgba(0,0,0,0)',\n", + " )\n", + " \n", + " return go.Figure(data=traces, layout=layout)\n", + "\n", + "plotly_view()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Here the Matplotlib output is being rendered as PNG, but the rest are interactive, with hovering, zooming, and similar features (if allowed by the notebook viewer being used). Note that due to interactions between the various JS libraries used here, the Plotly output can get mixed up when resizing or reloading the page, but it should be reset if you adjust the year slider once you are done.\n", - "\n", - "We can also make these plots available as a standalone server, if we add `.servable()` to the panel object and call this notebook as `bokeh serve --show Panel_Gapminders.ipynb`. Before doing that, let's make another panel where we can add a logo and a title, so that it makes a nicer page layout when served separately. We'll also add an R ggplot2-based plot to fill out the page:" + "Let's define the **Altair** plotting function." ] }, { @@ -196,37 +235,90 @@ "metadata": {}, "outputs": [], "source": [ - "logo = \"\"\"\n", - " \"\"\"\n", - "\n", - "title = '

Plotting library comparison

'\n", + "@pn.cache\n", + "def altair_view(year=1952, show_legend=True, height=\"container\", width=\"container\"):\n", + " data = get_data(year)\n", + " title = get_title(\"Altair/ Vega\", year)\n", + " legend= ({} if show_legend else {'legend': None})\n", + " return (\n", + " alt.Chart(data)\n", + " .mark_circle().encode(\n", + " alt.X('gdpPercap:Q', scale=alt.Scale(type='log'), axis=alt.Axis(title=XLABEL)),\n", + " alt.Y('lifeExp:Q', scale=alt.Scale(zero=False, domain=YLIM), axis=alt.Axis(title=YLABEL)),\n", + " size=alt.Size('pop:Q', scale=alt.Scale(type=\"log\"), legend=None),\n", + " color=alt.Color('continent', scale=alt.Scale(scheme=\"category10\"), **legend),\n", + " tooltip=['continent','country'])\n", + " .configure_axis(grid=False)\n", + " .properties(title=title, height=height, width=width, background='rgba(0,0,0,0)') \n", + " .configure_view(fill=\"white\")\n", + " .interactive()\n", + " )\n", "\n", - "desc = pn.pane.HTML(\"\"\"\n", - " The
Panel library from PyViz \n", - " lets you make widget-controlled apps and dashboards from a wide variety of \n", - " plotting libraries and data types. Here you can try out five different plotting libraries\n", - " controlled by a couple of widgets, for Hans Rosling's \n", - " gapminder example.\"\"\", width=250)\n", + "altair_view(height=HEIGHT-100, width=1000)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's define the **hvPlot** plotting function. Please note that [hvPlot](https://hvplot.holoviz.org/) is the recommended entry point to the HoloViz plotting ecosystem." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "@pn.cache\n", + "def hvplot_view(year=1952, show_legend=True):\n", + " data = get_data(year)\n", + " title = get_title(\"hvPlot/ Bokeh\", year)\n", + " xlim = get_xlim(data)\n", + " return data.hvplot.scatter(\n", + " 'gdpPercap', 'lifeExp', by='continent', s='size_hvplot', alpha=0.8,\n", + " logx=True, title=title, responsive=True, legend='bottom_right',\n", + " hover_cols=['country'], ylim=YLIM, xlim=xlim, ylabel=YLABEL, xlabel=XLABEL\n", + " )\n", "\n", - "widgets = pn.Param(gm.param, widgets={'year': {'type': pn.widgets.DiscreteSlider, 'width': 250}}, margin=0)\n", "\n", - "pn.Row(\n", - " pn.Column(logo, title, desc, widgets),\n", - " pn.Column(\n", - " pn.Row(gm.hvplot_view, gm.altair_view),\n", - " pn.Row(gm.mpl_view, gm.plotly_view)\n", - " )\n", - ")" + "hvplot_view().opts(height=400)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Template\n", + "## Define the widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "year = pn.widgets.DiscreteSlider(value=YEARS[-1], options=YEARS, name=\"Year\")\n", + "show_legend = pn.widgets.Checkbox(value=True, name=\"Show Legend\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def play():\n", + " print(\"play\")\n", + " if year.value == YEARS[-1]:\n", + " year.value=YEARS[0]\n", + " return\n", + " \n", + " index = YEARS.index(year.value)\n", + " year.value = YEARS[index+1] \n", "\n", - "To make the application look more polished we can put our components into a template:" + "periodic_callback = pn.state.add_periodic_callback(play, start=False, period=PERIOD)\n", + "player = pn.widgets.Checkbox.from_param(periodic_callback.param.running, name=\"Autoplay\")" ] }, { @@ -235,44 +327,150 @@ "metadata": {}, "outputs": [], "source": [ - "template = pn.template.MaterialTemplate(\n", - " title='Gapminder - Plotting library comparison',\n", + "widgets = pn.Column(year, player, show_legend, margin=(0,15))\n", + "widgets" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bind the plot functions to the widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mpl_view = pn.bind(mpl_view, year=year, show_legend=show_legend)\n", + "plotly_view = pn.bind(plotly_view, year=year, show_legend=show_legend)\n", + "altair_view = pn.bind(altair_view, year=year, show_legend=show_legend)\n", + "hvplot_view = pn.bind(hvplot_view, year=year, show_legend=show_legend)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Layout the widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "logo = pn.pane.PNG(\n", + " \"https://panel.holoviz.org/_static/logo_stacked.png\",\n", + " link_url=\"https://panel.holoviz.org\", embed=False, width=150, align=\"center\"\n", ")\n", + " \n", + "desc = \"\"\"## 🎓 Info\n", "\n", - "template.sidebar.append(logo)\n", - "template.sidebar.append(desc.clone(width=250, margin=(20, 5)))\n", + "The [Panel](http://panel.holoviz.org) library from [HoloViz](https://holoviz.org)\n", + "lets you make widget-controlled apps and dashboards from a wide variety of \n", + "plotting libraries and data types. Here you can try out four different plotting libraries\n", + "controlled by a couple of widgets, for Hans Rosling's \n", + "[gapminder](https://demo.bokeh.org/gapminder) example.\n", + "\"\"\"\n", "\n", - "template.sidebar.append(widgets)\n", + "settings = pn.Column(logo, \"## ⚙️ Settings\", widgets, desc)\n", + "settings" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Layout the plots\n", "\n", - "template.main.append(\n", - " pn.Column(\n", - " pn.Row(gm.hvplot_view, gm.altair_view),\n", - " pn.Row(gm.mpl_view, gm.plotly_view)\n", - " )\n", + "We layout the plots in a [Gridbox](https://panel.holoviz.org/reference/layouts/GridBox.html) with 2 columns. Please note Panel provides many other [layouts](https://panel.holoviz.org/reference/index.html#layouts) that might be perfect for your use case." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plots = pn.layout.GridBox(\n", + " pn.pane.Matplotlib(mpl_view, format='png', sizing_mode='scale_both', tight=True, margin=10),\n", + " pn.pane.HoloViews(hvplot_view, sizing_mode='stretch_both', margin=10),\n", + " pn.pane.Plotly(plotly_view, sizing_mode='stretch_both', margin=10),\n", + " pn.pane.Vega(altair_view, sizing_mode='stretch_both', margin=10),\n", + " ncols=2,\n", + " sizing_mode=\"stretch_both\"\n", ")\n", + "plots" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configure the template\n", "\n", - "template.servable();" + "Let us layout out the app in the nicely styled [FastListTemplate](https://panel.holoviz.org/reference/templates/FastListTemplate.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pn.template.FastListTemplate(\n", + " sidebar=[settings],\n", + " main=[plots],\n", + " site=\"Panel\",\n", + " site_url=\"https://panel.holoviz.org\",\n", + " title=\"Hans Rosling's Gapminder\",\n", + " header_background=ACCENT,\n", + " accent_base_color=ACCENT,\n", + " favicon=\"static/extensions/panel/images/favicon.ico\",\n", + " theme_toggle=False,\n", + ").servable(); # We add ; to avoid showing the app in the notebook" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Once you run `panel serve` on this notebook , you should get a panel like the following in your web browser that you can explore or share with other users of your machine:" + "The final data app can be served via `panel serve gapminders.ipynb`.\n", + "\n", + "It will look something like." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "" + "\"Gapminder" ] } ], "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", - "pygments_lexer": "ipython3" + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.18" } }, "nbformat": 4,