diff --git a/world_cup/anaconda-project-lock.yml b/world_cup/anaconda-project-lock.yml
index d35391bc9..6084693bc 100644
--- a/world_cup/anaconda-project-lock.yml
+++ b/world_cup/anaconda-project-lock.yml
@@ -17,7 +17,7 @@ locking_enabled: true
env_specs:
default:
locked: true
- env_spec_hash: 0ff5c425f37c39698546b229288c66045beb125f
+ env_spec_hash: 4627f68b15ca2427657a29bdebcce3d6e2b8dbe6
platforms:
- linux-64
- osx-64
@@ -27,61 +27,62 @@ env_specs:
all:
- argon2-cffi=21.3.0=pyhd3eb1b0_0
- asttokens=2.0.5=pyhd3eb1b0_0
- - bleach=4.1.0=pyhd3eb1b0_0
- - charset-normalizer=2.0.4=pyhd3eb1b0_0
+ - charset-normalizer=3.3.2=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
- ipython_genutils=0.2.0=pyhd3eb1b0_1
- pandocfilters=1.5.0=pyhd3eb1b0_0
- - parso=0.8.3=pyhd3eb1b0_0
- prompt_toolkit=3.0.43=hd3eb1b0_0
- pure_eval=0.2.2=pyhd3eb1b0_0
- pycparser=2.21=pyhd3eb1b0_0
- python-tzdata=2023.3=pyhd3eb1b0_0
- six=1.16.0=pyhd3eb1b0_1
- stack_data=0.2.0=pyhd3eb1b0_0
- - tzdata=2024a=h04d1e81_0
+ - tzdata=2024b=h04d1e81_0
- wcwidth=0.2.5=pyhd3eb1b0_0
unix:
- pexpect=4.8.0=pyhd3eb1b0_3
- ptyprocess=0.7.0=pyhd3eb1b0_2
+ osx:
+ - blas=1.0=openblas
linux-64:
- _libgcc_mutex=0.1=main
- _openmp_mutex=5.1=1_gnu
- - anyio=4.2.0=py311h06a4308_0
- - argon2-cffi-bindings=21.2.0=py311h5eee18b_0
- - attrs=23.1.0=py311h06a4308_0
+ - anyio=4.6.2=py311h06a4308_0
+ - argon2-cffi-bindings=21.2.0=py311h5eee18b_1
+ - attrs=24.3.0=py311h06a4308_0
- beautifulsoup4=4.12.3=py311h06a4308_0
- blas=1.0=mkl
- - bokeh=3.4.1=py311h92b7b1e_0
- - bottleneck=1.3.7=py311hf4808d0_0
- - brotli-bin=1.0.9=h5eee18b_8
- - brotli-python=1.0.9=py311h6a678d5_8
- - brotli=1.0.9=h5eee18b_8
+ - bleach=6.2.0=py311h06a4308_0
+ - bokeh=3.6.0=py311h06a4308_0
+ - bottleneck=1.4.2=py311hf4808d0_0
+ - brotli-bin=1.0.9=h5eee18b_9
+ - brotli-python=1.0.9=py311h6a678d5_9
+ - brotli=1.0.9=h5eee18b_9
- bzip2=1.0.8=h5eee18b_6
- - ca-certificates=2024.7.2=h06a4308_0
- - certifi=2024.7.4=py311h06a4308_0
- - cffi=1.16.0=py311h5eee18b_1
+ - ca-certificates=2024.12.31=h06a4308_0
+ - certifi=2024.12.14=py311h06a4308_0
+ - cffi=1.17.1=py311h1fdaa30_1
- colorcet=3.1.0=py311h06a4308_0
- comm=0.2.1=py311h06a4308_0
- - contourpy=1.2.0=py311hdb19cb5_0
- - debugpy=1.6.7=py311h6a678d5_0
+ - contourpy=1.3.1=py311hdb19cb5_0
+ - debugpy=1.8.11=py311h6a678d5_0
- entrypoints=0.4=py311h06a4308_0
- fonttools=4.51.0=py311h5eee18b_0
- freetype=2.12.1=h4a9f257_0
- - holoviews=1.19.1=py311h06a4308_0
- - hvplot=0.10.0=py311h06a4308_0
+ - holoviews=1.20.0=py311h06a4308_0
+ - hvplot=0.11.2=py311h06a4308_0
- idna=3.7=py311h06a4308_0
- intel-openmp=2023.1.0=hdb19cb5_46306
- - ipykernel=6.28.0=py311h06a4308_0
- - ipython=8.25.0=py311h06a4308_0
- - jedi=0.19.1=py311h06a4308_0
- - jinja2=3.1.4=py311h06a4308_0
- - jpeg=9e=h5eee18b_1
+ - ipykernel=6.29.5=py311h06a4308_0
+ - ipython=8.30.0=py311h06a4308_0
+ - jedi=0.19.2=py311h06a4308_0
+ - jinja2=3.1.4=py311h06a4308_1
+ - jpeg=9e=h5eee18b_3
- jsonschema-specifications=2023.7.1=py311h06a4308_0
- - jsonschema=4.19.2=py311h06a4308_0
+ - jsonschema=4.23.0=py311h06a4308_0
- jupyter_client=7.4.9=py311h06a4308_0
- jupyter_core=5.7.2=py311h06a4308_0
- jupyter_events=0.10.0=py311h06a4308_0
@@ -89,79 +90,80 @@ env_specs:
- jupyter_server_terminals=0.4.4=py311h06a4308_1
- jupyterlab_pygments=0.2.2=py311h06a4308_0
- kiwisolver=1.4.4=py311h6a678d5_0
- - lcms2=2.12=h3be6417_0
- - ld_impl_linux-64=2.38=h1181459_1
- - lerc=3.0=h295c915_0
- - libbrotlicommon=1.0.9=h5eee18b_8
- - libbrotlidec=1.0.9=h5eee18b_8
- - libbrotlienc=1.0.9=h5eee18b_8
- - libdeflate=1.17=h5eee18b_1
+ - lcms2=2.16=hb9589c4_0
+ - ld_impl_linux-64=2.40=h12ee557_0
+ - lerc=4.0.0=h6a678d5_0
+ - libbrotlicommon=1.0.9=h5eee18b_9
+ - libbrotlidec=1.0.9=h5eee18b_9
+ - libbrotlienc=1.0.9=h5eee18b_9
+ - libdeflate=1.22=h5eee18b_0
- libffi=3.4.4=h6a678d5_1
- 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
+ - libtiff=4.5.1=hffd6297_1
- libuuid=1.41.5=h5eee18b_0
- - libwebp-base=1.3.2=h5eee18b_0
+ - libwebp-base=1.3.2=h5eee18b_1
- linkify-it-py=2.0.0=py311h06a4308_0
- lz4-c=1.9.4=h6a678d5_1
- markdown-it-py=2.2.0=py311h06a4308_1
- markdown=3.4.1=py311h06a4308_0
- - markupsafe=2.1.3=py311h5eee18b_0
- - matplotlib-base=3.8.4=py311ha02d727_0
+ - markupsafe=2.1.3=py311h5eee18b_1
+ - matplotlib-base=3.10.0=py311hbfdbfaf_0
- matplotlib-inline=0.1.6=py311h06a4308_0
- mdit-py-plugins=0.3.0=py311h06a4308_0
- mdurl=0.1.0=py311h06a4308_0
- mistune=2.0.4=py311h06a4308_0
- - mkl-service=2.4.0=py311h5eee18b_1
+ - mkl-service=2.4.0=py311h5eee18b_2
- mkl=2023.1.0=h213fc3f_46344
- - mkl_fft=1.3.8=py311h5eee18b_0
- - mkl_random=1.2.4=py311hdb19cb5_0
+ - mkl_fft=1.3.11=py311h5eee18b_0
+ - mkl_random=1.2.8=py311ha02d727_0
- nbclassic=1.1.0=py311h06a4308_0
- nbclient=0.8.0=py311h06a4308_0
- - nbconvert=7.10.0=py311h06a4308_0
- - nbformat=5.9.2=py311h06a4308_0
+ - nbconvert=7.16.4=py311h06a4308_0
+ - nbformat=5.10.4=py311h06a4308_0
- ncurses=6.4=h6a678d5_0
- nest-asyncio=1.6.0=py311h06a4308_0
- notebook-shim=0.2.3=py311h06a4308_0
- notebook=6.5.7=py311h06a4308_0
- - numexpr=2.8.7=py311h65dcdc2_0
- - numpy-base=1.26.4=py311hf175353_0
- - numpy=1.26.4=py311h08b1b3b_0
- - openjpeg=2.4.0=h9ca470c_2
- - openssl=3.0.14=h5eee18b_0
+ - numexpr=2.10.1=py311h3c60e43_0
+ - numpy-base=2.2.1=py311hf175353_0
+ - numpy=2.2.1=py311h08b1b3b_0
+ - openjpeg=2.5.2=he7f1fd0_0
+ - openssl=3.0.15=h5eee18b_0
- overrides=7.4.0=py311h06a4308_0
- - packaging=24.1=py311h06a4308_0
- - pandas=2.2.2=py311ha02d727_0
- - panel=1.4.4=py311h06a4308_0
- - param=2.1.1=py311h06a4308_0
- - pillow=10.4.0=py311h5eee18b_0
- - pip=24.0=py311h06a4308_0
+ - packaging=24.2=py311h06a4308_0
+ - pandas=2.2.3=py311h6a678d5_0
+ - panel=1.5.3=py311h06a4308_0
+ - param=2.2.0=py311h06a4308_0
+ - parso=0.8.4=py311h06a4308_0
+ - pillow=11.0.0=py311hcea889d_1
+ - pip=24.2=py311h06a4308_0
- platformdirs=3.10.0=py311h06a4308_0
- - prometheus_client=0.14.1=py311h06a4308_0
+ - prometheus_client=0.21.0=py311h06a4308_0
- prompt-toolkit=3.0.43=py311h06a4308_0
- - psutil=5.9.0=py311h5eee18b_0
+ - psutil=5.9.0=py311h5eee18b_1
- pygments=2.15.1=py311h06a4308_1
- - pyparsing=3.0.9=py311h06a4308_0
+ - pyparsing=3.2.0=py311h06a4308_0
- pysocks=1.7.1=py311h06a4308_0
- python-dateutil=2.9.0post0=py311h06a4308_2
- - python-fastjsonschema=2.16.2=py311h06a4308_0
- - python-json-logger=2.0.7=py311h06a4308_0
- - python=3.11.9=h955ad1f_0
+ - python-fastjsonschema=2.20.0=py311h06a4308_0
+ - python-json-logger=3.2.1=py311h06a4308_0
+ - python=3.11.11=he870216_0
- pytz=2024.1=py311h06a4308_0
- pyviz_comms=3.0.2=py311h06a4308_0
- - pyyaml=6.0.1=py311h5eee18b_0
+ - pyyaml=6.0.2=py311h5eee18b_0
- pyzmq=24.0.1=py311h5eee18b_0
- readline=8.2=h5eee18b_0
- referencing=0.30.2=py311h06a4308_0
- - requests=2.32.2=py311h06a4308_0
+ - requests=2.32.3=py311h06a4308_1
- rfc3339-validator=0.1.4=py311h06a4308_0
- rfc3986-validator=0.1.1=py311h06a4308_0
- - rpds-py=0.10.6=py311hb02cf49_0
+ - rpds-py=0.10.6=py311h4aa5aa6_1
- send2trash=1.8.2=py311h06a4308_0
- - setuptools=69.5.1=py311h06a4308_0
+ - setuptools=72.1.0=py311h06a4308_0
- sniffio=1.3.0=py311h06a4308_0
- soupsieve=2.5=py311h06a4308_0
- sqlite=3.45.3=h5eee18b_0
@@ -169,57 +171,56 @@ env_specs:
- terminado=0.17.1=py311h06a4308_0
- tinycss2=1.2.1=py311h06a4308_0
- tk=8.6.14=h39e8969_0
- - tornado=6.4.1=py311h5eee18b_0
- - tqdm=4.66.4=py311h92b7b1e_0
+ - tornado=6.4.2=py311h5eee18b_0
+ - tqdm=4.66.5=py311h92b7b1e_0
- traitlets=5.14.3=py311h06a4308_0
- - typing-extensions=4.11.0=py311h06a4308_0
- - typing_extensions=4.11.0=py311h06a4308_0
+ - typing-extensions=4.12.2=py311h06a4308_0
+ - typing_extensions=4.12.2=py311h06a4308_0
- uc-micro-py=1.0.1=py311h06a4308_0
- unicodedata2=15.1.0=py311h5eee18b_0
- - urllib3=2.2.2=py311h06a4308_0
+ - urllib3=2.2.3=py311h06a4308_0
- webencodings=0.5.1=py311h06a4308_1
- websocket-client=1.8.0=py311h06a4308_0
- - wheel=0.43.0=py311h06a4308_0
+ - wheel=0.44.0=py311h06a4308_0
- xyzservices=2022.9.0=py311h06a4308_1
- xz=5.4.6=h5eee18b_1
- yaml=0.2.5=h7b6447c_0
- zeromq=4.3.5=h6a678d5_0
- zlib=1.2.13=h5eee18b_1
- - zstd=1.5.5=hc292b87_2
+ - zstd=1.5.6=hc292b87_0
osx-64:
- - anyio=4.2.0=py311hecd8cb5_0
+ - anyio=4.6.2=py311hecd8cb5_0
- appnope=0.1.2=py311hecd8cb5_1001
- - argon2-cffi-bindings=21.2.0=py311h6c40b1e_0
- - attrs=23.1.0=py311hecd8cb5_0
+ - argon2-cffi-bindings=21.2.0=py311h46256e1_1
+ - attrs=24.3.0=py311hecd8cb5_0
- beautifulsoup4=4.12.3=py311hecd8cb5_0
- - blas=1.0=mkl
- - bokeh=3.4.1=py311h85bffb1_0
- - bottleneck=1.3.7=py311hb3a5e46_0
- - brotli-bin=1.0.9=h6c40b1e_8
- - brotli-python=1.0.9=py311hcec6c5f_8
- - brotli=1.0.9=h6c40b1e_8
+ - bleach=6.2.0=py311hecd8cb5_0
+ - bokeh=3.6.0=py311hecd8cb5_0
+ - bottleneck=1.4.2=py311h9b7fc35_0
+ - brotli-bin=1.0.9=h46256e1_9
+ - brotli-python=1.0.9=py311h6d0c2b6_9
+ - brotli=1.0.9=h46256e1_9
- bzip2=1.0.8=h6c40b1e_6
- - ca-certificates=2024.7.2=hecd8cb5_0
- - certifi=2024.7.4=py311hecd8cb5_0
- - cffi=1.16.0=py311h6c40b1e_1
+ - ca-certificates=2024.12.31=hecd8cb5_0
+ - certifi=2024.12.14=py311hecd8cb5_0
+ - cffi=1.17.1=py311h9205ec4_1
- colorcet=3.1.0=py311hecd8cb5_0
- comm=0.2.1=py311hecd8cb5_0
- - contourpy=1.2.0=py311ha357a0b_0
- - debugpy=1.6.7=py311hcec6c5f_0
+ - contourpy=1.3.1=py311h1962661_0
+ - debugpy=1.8.11=py311h6d0c2b6_0
- entrypoints=0.4=py311hecd8cb5_0
- fonttools=4.51.0=py311h6c40b1e_0
- freetype=2.12.1=hd8bbffd_0
- - holoviews=1.19.1=py311hecd8cb5_0
- - hvplot=0.10.0=py311hecd8cb5_0
+ - holoviews=1.20.0=py311hecd8cb5_0
+ - hvplot=0.11.2=py311hecd8cb5_0
- idna=3.7=py311hecd8cb5_0
- - intel-openmp=2023.1.0=ha357a0b_43548
- - ipykernel=6.28.0=py311hecd8cb5_0
- - ipython=8.25.0=py311hecd8cb5_0
- - jedi=0.19.1=py311hecd8cb5_0
- - jinja2=3.1.4=py311hecd8cb5_0
- - jpeg=9e=h6c40b1e_1
+ - ipykernel=6.29.5=py311hecd8cb5_0
+ - ipython=8.30.0=py311hecd8cb5_0
+ - jedi=0.19.2=py311hecd8cb5_0
+ - jinja2=3.1.4=py311hecd8cb5_1
+ - jpeg=9e=h46256e1_3
- jsonschema-specifications=2023.7.1=py311hecd8cb5_0
- - jsonschema=4.19.2=py311hecd8cb5_0
+ - jsonschema=4.23.0=py311hecd8cb5_0
- jupyter_client=7.4.9=py311hecd8cb5_0
- jupyter_core=5.7.2=py311hecd8cb5_0
- jupyter_events=0.10.0=py311hecd8cb5_0
@@ -227,132 +228,132 @@ env_specs:
- jupyter_server_terminals=0.4.4=py311hecd8cb5_1
- jupyterlab_pygments=0.2.2=py311hecd8cb5_0
- kiwisolver=1.4.4=py311hcec6c5f_0
- - lcms2=2.12=hf1fd2bf_0
- - lerc=3.0=he9d5cce_0
- - libbrotlicommon=1.0.9=h6c40b1e_8
- - libbrotlidec=1.0.9=h6c40b1e_8
- - libbrotlienc=1.0.9=h6c40b1e_8
+ - lcms2=2.16=h4f63f0c_0
+ - lerc=4.0.0=h6d0c2b6_0
+ - libbrotlicommon=1.0.9=h46256e1_9
+ - libbrotlidec=1.0.9=h46256e1_9
+ - libbrotlienc=1.0.9=h46256e1_9
- libcxx=14.0.6=h9765a3e_0
- - libdeflate=1.17=hb664fd8_1
+ - libdeflate=1.22=h46256e1_0
- libffi=3.4.4=hecd8cb5_1
+ - libgfortran5=11.3.0=h9dfd629_28
+ - libgfortran=5.0.0=11_3_0_hecd8cb5_28
+ - libopenblas=0.3.21=h54e7dc3_0
- 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
+ - libtiff=4.5.1=h6fa9cd1_1
+ - libwebp-base=1.3.2=h46256e1_1
- linkify-it-py=2.0.0=py311hecd8cb5_0
+ - llvm-openmp=14.0.6=h0dcd299_0
- lz4-c=1.9.4=hcec6c5f_1
- markdown-it-py=2.2.0=py311hecd8cb5_1
- markdown=3.4.1=py311hecd8cb5_0
- - markupsafe=2.1.3=py311h6c40b1e_0
- - matplotlib-base=3.8.4=py311h41a4f6b_0
+ - markupsafe=2.1.3=py311h46256e1_1
+ - matplotlib-base=3.10.0=py311h919b35b_0
- matplotlib-inline=0.1.6=py311hecd8cb5_0
- mdit-py-plugins=0.3.0=py311hecd8cb5_0
- mdurl=0.1.0=py311hecd8cb5_0
- mistune=2.0.4=py311hecd8cb5_0
- - mkl-service=2.4.0=py311h6c40b1e_1
- - mkl=2023.1.0=h8e150cf_43560
- - mkl_fft=1.3.8=py311h6c40b1e_0
- - mkl_random=1.2.4=py311ha357a0b_0
- nbclassic=1.1.0=py311hecd8cb5_0
- nbclient=0.8.0=py311hecd8cb5_0
- - nbconvert=7.10.0=py311hecd8cb5_0
- - nbformat=5.9.2=py311hecd8cb5_0
+ - nbconvert=7.16.4=py311hecd8cb5_0
+ - nbformat=5.10.4=py311hecd8cb5_0
- ncurses=6.4=hcec6c5f_0
- nest-asyncio=1.6.0=py311hecd8cb5_0
- notebook-shim=0.2.3=py311hecd8cb5_0
- notebook=6.5.7=py311hecd8cb5_0
- - numexpr=2.8.7=py311h728a8a3_0
- - numpy-base=1.26.4=py311h53bf9ac_0
- - numpy=1.26.4=py311h728a8a3_0
- - openjpeg=2.4.0=h7231236_2
- - openssl=3.0.14=h46256e1_0
+ - numexpr=2.10.1=py311hc59c7be_0
+ - numpy-base=2.1.3=py311ha745260_0
+ - numpy=2.1.3=py311h13f252e_0
+ - openjpeg=2.5.2=hbf2204d_0
+ - openssl=3.0.15=h46256e1_0
- overrides=7.4.0=py311hecd8cb5_0
- - packaging=24.1=py311hecd8cb5_0
- - pandas=2.2.2=py311he327ffe_0
- - panel=1.4.4=py311hecd8cb5_0
- - param=2.1.1=py311hecd8cb5_0
- - pillow=10.4.0=py311h46256e1_0
- - pip=24.0=py311hecd8cb5_0
+ - packaging=24.2=py311hecd8cb5_0
+ - pandas=2.2.3=py311h6d0c2b6_0
+ - panel=1.5.3=py311hecd8cb5_0
+ - param=2.2.0=py311hecd8cb5_0
+ - parso=0.8.4=py311hecd8cb5_0
+ - pillow=11.0.0=py311h47bf62f_1
+ - pip=24.2=py311hecd8cb5_0
- platformdirs=3.10.0=py311hecd8cb5_0
- - prometheus_client=0.14.1=py311hecd8cb5_0
+ - prometheus_client=0.21.0=py311hecd8cb5_0
- prompt-toolkit=3.0.43=py311hecd8cb5_0
- - psutil=5.9.0=py311h6c40b1e_0
+ - psutil=5.9.0=py311h46256e1_1
- pygments=2.15.1=py311hecd8cb5_1
- - pyparsing=3.0.9=py311hecd8cb5_0
+ - pyparsing=3.2.0=py311hecd8cb5_0
- pysocks=1.7.1=py311hecd8cb5_0
- python-dateutil=2.9.0post0=py311hecd8cb5_2
- - python-fastjsonschema=2.16.2=py311hecd8cb5_0
- - python-json-logger=2.0.7=py311hecd8cb5_0
- - python=3.11.9=hf27a42d_0
+ - python-fastjsonschema=2.20.0=py311hecd8cb5_0
+ - python-json-logger=3.2.1=py311hecd8cb5_0
+ - python=3.11.11=h4d6d9e5_0
- pytz=2024.1=py311hecd8cb5_0
- pyviz_comms=3.0.2=py311hecd8cb5_0
- - pyyaml=6.0.1=py311h6c40b1e_0
+ - pyyaml=6.0.2=py311h46256e1_0
- pyzmq=24.0.1=py311h6c40b1e_0
- readline=8.2=hca72f7f_0
- referencing=0.30.2=py311hecd8cb5_0
- - requests=2.32.2=py311hecd8cb5_0
+ - requests=2.32.3=py311hecd8cb5_1
- rfc3339-validator=0.1.4=py311hecd8cb5_0
- rfc3986-validator=0.1.1=py311hecd8cb5_0
- - rpds-py=0.10.6=py311hf2ad997_0
+ - rpds-py=0.10.6=py311h83de92b_1
- send2trash=1.8.2=py311hecd8cb5_0
- - setuptools=69.5.1=py311hecd8cb5_0
+ - setuptools=72.1.0=py311hecd8cb5_0
- sniffio=1.3.0=py311hecd8cb5_0
- soupsieve=2.5=py311hecd8cb5_0
- sqlite=3.45.3=h6c40b1e_0
- - tbb=2021.8.0=ha357a0b_0
- terminado=0.17.1=py311hecd8cb5_0
- tinycss2=1.2.1=py311hecd8cb5_0
- tk=8.6.14=h4d00af3_0
- - tornado=6.4.1=py311h46256e1_0
- - tqdm=4.66.4=py311h85bffb1_0
+ - tornado=6.4.2=py311h46256e1_0
+ - tqdm=4.66.5=py311h85bffb1_0
- traitlets=5.14.3=py311hecd8cb5_0
- - typing-extensions=4.11.0=py311hecd8cb5_0
- - typing_extensions=4.11.0=py311hecd8cb5_0
+ - typing-extensions=4.12.2=py311hecd8cb5_0
+ - typing_extensions=4.12.2=py311hecd8cb5_0
- uc-micro-py=1.0.1=py311hecd8cb5_0
- unicodedata2=15.1.0=py311h6c40b1e_0
- - urllib3=2.2.2=py311hecd8cb5_0
+ - urllib3=2.2.3=py311hecd8cb5_0
- webencodings=0.5.1=py311hecd8cb5_1
- websocket-client=1.8.0=py311hecd8cb5_0
- - wheel=0.43.0=py311hecd8cb5_0
+ - wheel=0.44.0=py311hecd8cb5_0
- xyzservices=2022.9.0=py311hecd8cb5_1
- xz=5.4.6=h6c40b1e_1
- yaml=0.2.5=haf1e3a3_0
- zeromq=4.3.5=hcec6c5f_0
- zlib=1.2.13=h4b97444_1
- - zstd=1.5.5=hc035e20_2
+ - zstd=1.5.6=h138b38a_0
osx-arm64:
- - anyio=4.2.0=py311hca03da5_0
+ - anyio=4.6.2=py311hca03da5_0
- appnope=0.1.2=py311hca03da5_1001
- - argon2-cffi-bindings=21.2.0=py311h80987f9_0
- - attrs=23.1.0=py311hca03da5_0
+ - argon2-cffi-bindings=21.2.0=py311h80987f9_1
+ - attrs=24.3.0=py311hca03da5_0
- beautifulsoup4=4.12.3=py311hca03da5_0
- - blas=1.0=openblas
- - bokeh=3.4.1=py311hb6e6a13_0
- - bottleneck=1.3.7=py311hb9f6ed7_0
- - brotli-bin=1.0.9=h80987f9_8
- - brotli-python=1.0.9=py311h313beb8_8
- - brotli=1.0.9=h80987f9_8
+ - bleach=6.2.0=py311hca03da5_0
+ - bokeh=3.6.0=py311hca03da5_0
+ - bottleneck=1.4.2=py311hb9f6ed7_0
+ - brotli-bin=1.0.9=h80987f9_9
+ - brotli-python=1.0.9=py311h313beb8_9
+ - brotli=1.0.9=h80987f9_9
- bzip2=1.0.8=h80987f9_6
- - ca-certificates=2024.7.2=hca03da5_0
- - certifi=2024.7.4=py311hca03da5_0
- - cffi=1.16.0=py311h80987f9_1
+ - ca-certificates=2024.12.31=hca03da5_0
+ - certifi=2024.12.14=py311hca03da5_0
+ - cffi=1.17.1=py311h3eb5a62_1
- colorcet=3.1.0=py311hca03da5_0
- comm=0.2.1=py311hca03da5_0
- - contourpy=1.2.0=py311h48ca7d4_0
- - debugpy=1.6.7=py311h313beb8_0
+ - contourpy=1.3.1=py311h48ca7d4_0
+ - debugpy=1.8.11=py311h313beb8_0
- entrypoints=0.4=py311hca03da5_0
- fonttools=4.51.0=py311h80987f9_0
- freetype=2.12.1=h1192e45_0
- - holoviews=1.19.1=py311hca03da5_0
- - hvplot=0.10.0=py311hca03da5_0
+ - holoviews=1.20.0=py311hca03da5_0
+ - hvplot=0.11.2=py311hca03da5_0
- idna=3.7=py311hca03da5_0
- - ipykernel=6.28.0=py311hca03da5_0
- - ipython=8.25.0=py311hca03da5_0
- - jedi=0.19.1=py311hca03da5_0
- - jinja2=3.1.4=py311hca03da5_0
- - jpeg=9e=h80987f9_1
+ - ipykernel=6.29.5=py311hca03da5_0
+ - ipython=8.30.0=py311hca03da5_0
+ - jedi=0.19.2=py311hca03da5_0
+ - jinja2=3.1.4=py311hca03da5_1
+ - jpeg=9e=h80987f9_3
- jsonschema-specifications=2023.7.1=py311hca03da5_0
- - jsonschema=4.19.2=py311hca03da5_0
+ - jsonschema=4.23.0=py311hca03da5_0
- jupyter_client=7.4.9=py311hca03da5_0
- jupyter_core=5.7.2=py311hca03da5_0
- jupyter_events=0.10.0=py311hca03da5_0
@@ -360,132 +361,134 @@ env_specs:
- jupyter_server_terminals=0.4.4=py311hca03da5_1
- jupyterlab_pygments=0.2.2=py311hca03da5_0
- kiwisolver=1.4.4=py311h313beb8_0
- - lcms2=2.12=hba8e193_0
- - lerc=3.0=hc377ac9_0
- - libbrotlicommon=1.0.9=h80987f9_8
- - libbrotlidec=1.0.9=h80987f9_8
- - libbrotlienc=1.0.9=h80987f9_8
+ - lcms2=2.16=he93ba84_0
+ - lerc=4.0.0=h313beb8_0
+ - libbrotlicommon=1.0.9=h80987f9_9
+ - libbrotlidec=1.0.9=h80987f9_9
+ - libbrotlienc=1.0.9=h80987f9_9
- libcxx=14.0.6=h848a8c0_0
- - libdeflate=1.17=h80987f9_1
+ - libdeflate=1.22=h80987f9_0
- libffi=3.4.4=hca03da5_1
- libgfortran5=11.3.0=h009349e_28
- libgfortran=5.0.0=11_3_0_hca03da5_28
- 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
+ - libtiff=4.5.1=hc9ead59_1
+ - libwebp-base=1.3.2=h80987f9_1
- linkify-it-py=2.0.0=py311hca03da5_0
- llvm-openmp=14.0.6=hc6e5704_0
- lz4-c=1.9.4=h313beb8_1
- markdown-it-py=2.2.0=py311hca03da5_1
- markdown=3.4.1=py311hca03da5_0
- markupsafe=2.1.3=py311h80987f9_0
- - matplotlib-base=3.8.4=py311h7aedaa7_0
+ - matplotlib-base=3.10.0=py311h7ef442a_0
- matplotlib-inline=0.1.6=py311hca03da5_0
- mdit-py-plugins=0.3.0=py311hca03da5_0
- mdurl=0.1.0=py311hca03da5_0
- mistune=2.0.4=py311hca03da5_0
- nbclassic=1.1.0=py311hca03da5_0
- nbclient=0.8.0=py311hca03da5_0
- - nbconvert=7.10.0=py311hca03da5_0
- - nbformat=5.9.2=py311hca03da5_0
+ - nbconvert=7.16.4=py311hca03da5_0
+ - nbformat=5.10.4=py311hca03da5_0
- ncurses=6.4=h313beb8_0
- nest-asyncio=1.6.0=py311hca03da5_0
- notebook-shim=0.2.3=py311hca03da5_0
- notebook=6.5.7=py311hca03da5_0
- - numexpr=2.8.7=py311h6dc990b_0
- - numpy-base=1.26.4=py311hfbfe69c_0
- - numpy=1.26.4=py311he598dae_0
- - openjpeg=2.4.0=h0ed58ac_2
- - openssl=3.0.14=h80987f9_0
+ - numexpr=2.10.1=py311h5d9532f_0
+ - numpy-base=2.2.1=py311hfbfe69c_0
+ - numpy=2.2.1=py311he598dae_0
+ - openjpeg=2.5.2=h54b8e55_0
+ - openssl=3.0.15=h80987f9_0
- overrides=7.4.0=py311hca03da5_0
- - packaging=24.1=py311hca03da5_0
- - pandas=2.2.2=py311h7aedaa7_0
- - panel=1.4.4=py311hca03da5_0
- - param=2.1.1=py311hca03da5_0
- - pillow=10.4.0=py311h80987f9_0
- - pip=24.0=py311hca03da5_0
+ - packaging=24.2=py311hca03da5_0
+ - pandas=2.2.3=py311hcf29cfe_0
+ - panel=1.5.3=py311hca03da5_0
+ - param=2.2.0=py311hca03da5_0
+ - parso=0.8.4=py311hca03da5_0
+ - pillow=11.0.0=py311h84e58ab_1
+ - pip=24.2=py311hca03da5_0
- platformdirs=3.10.0=py311hca03da5_0
- - prometheus_client=0.14.1=py311hca03da5_0
+ - prometheus_client=0.21.0=py311hca03da5_0
- prompt-toolkit=3.0.43=py311hca03da5_0
- - psutil=5.9.0=py311h80987f9_0
+ - psutil=5.9.0=py311h80987f9_1
- pygments=2.15.1=py311hca03da5_1
- - pyparsing=3.0.9=py311hca03da5_0
+ - pyparsing=3.2.0=py311hca03da5_0
- pysocks=1.7.1=py311hca03da5_0
- python-dateutil=2.9.0post0=py311hca03da5_2
- - python-fastjsonschema=2.16.2=py311hca03da5_0
- - python-json-logger=2.0.7=py311hca03da5_0
- - python=3.11.9=hb885b13_0
+ - python-fastjsonschema=2.20.0=py311hca03da5_0
+ - python-json-logger=3.2.1=py311hca03da5_0
+ - python=3.11.11=hb885b13_0
- pytz=2024.1=py311hca03da5_0
- pyviz_comms=3.0.2=py311hca03da5_0
- - pyyaml=6.0.1=py311h80987f9_0
+ - pyyaml=6.0.2=py311h80987f9_0
- pyzmq=24.0.1=py311h80987f9_0
- readline=8.2=h1a28f6b_0
- referencing=0.30.2=py311hca03da5_0
- - requests=2.32.2=py311hca03da5_0
+ - requests=2.32.3=py311hca03da5_1
- rfc3339-validator=0.1.4=py311hca03da5_0
- rfc3986-validator=0.1.1=py311hca03da5_0
- - rpds-py=0.10.6=py311hf0e4da2_0
+ - rpds-py=0.10.6=py311h2aea54e_1
- send2trash=1.8.2=py311hca03da5_0
- - setuptools=69.5.1=py311hca03da5_0
+ - setuptools=72.1.0=py311hca03da5_0
- sniffio=1.3.0=py311hca03da5_0
- soupsieve=2.5=py311hca03da5_0
- sqlite=3.45.3=h80987f9_0
- terminado=0.17.1=py311hca03da5_0
- tinycss2=1.2.1=py311hca03da5_0
- tk=8.6.14=h6ba3021_0
- - tornado=6.4.1=py311h80987f9_0
- - tqdm=4.66.4=py311hb6e6a13_0
+ - tornado=6.4.2=py311h80987f9_0
+ - tqdm=4.66.5=py311hb6e6a13_0
- traitlets=5.14.3=py311hca03da5_0
- - typing-extensions=4.11.0=py311hca03da5_0
- - typing_extensions=4.11.0=py311hca03da5_0
+ - typing-extensions=4.12.2=py311hca03da5_0
+ - typing_extensions=4.12.2=py311hca03da5_0
- uc-micro-py=1.0.1=py311hca03da5_0
- unicodedata2=15.1.0=py311h80987f9_0
- - urllib3=2.2.2=py311hca03da5_0
+ - urllib3=2.2.3=py311hca03da5_0
- webencodings=0.5.1=py311hca03da5_1
- websocket-client=1.8.0=py311hca03da5_0
- - wheel=0.43.0=py311hca03da5_0
+ - wheel=0.44.0=py311hca03da5_0
- xyzservices=2022.9.0=py311hca03da5_1
- xz=5.4.6=h80987f9_1
- yaml=0.2.5=h1a28f6b_0
- zeromq=4.3.5=h313beb8_0
- zlib=1.2.13=h18a0788_1
- - zstd=1.5.5=hd90d995_2
+ - zstd=1.5.6=hfb09047_0
win-64:
- - anyio=4.2.0=py311haa95532_0
- - argon2-cffi-bindings=21.2.0=py311h2bbff1b_0
- - attrs=23.1.0=py311haa95532_0
+ - anyio=4.6.2=py311haa95532_0
+ - argon2-cffi-bindings=21.2.0=py311h827c3e9_1
+ - attrs=24.3.0=py311haa95532_0
- beautifulsoup4=4.12.3=py311haa95532_0
- blas=1.0=mkl
- - bokeh=3.4.1=py311h746a85d_0
- - bottleneck=1.3.7=py311hd7041d2_0
- - brotli-bin=1.0.9=h2bbff1b_8
- - brotli-python=1.0.9=py311hd77b12b_8
- - brotli=1.0.9=h2bbff1b_8
+ - bleach=6.2.0=py311haa95532_0
+ - bokeh=3.6.0=py311haa95532_0
+ - bottleneck=1.4.2=py311h57dcf0c_0
+ - brotli-bin=1.0.9=h827c3e9_9
+ - brotli-python=1.0.9=py311h5da7b33_9
+ - brotli=1.0.9=h827c3e9_9
- bzip2=1.0.8=h2bbff1b_6
- - ca-certificates=2024.7.2=haa95532_0
- - certifi=2024.7.4=py311haa95532_0
- - cffi=1.16.0=py311h2bbff1b_1
+ - ca-certificates=2024.12.31=haa95532_0
+ - certifi=2024.12.14=py311haa95532_0
+ - cffi=1.17.1=py311h827c3e9_1
- colorama=0.4.6=py311haa95532_0
- colorcet=3.1.0=py311haa95532_0
- comm=0.2.1=py311haa95532_0
- - contourpy=1.2.0=py311h59b6b97_0
- - debugpy=1.6.7=py311hd77b12b_0
+ - contourpy=1.3.1=py311h214f63a_0
+ - debugpy=1.8.11=py311h5da7b33_0
- entrypoints=0.4=py311haa95532_0
- fonttools=4.51.0=py311h2bbff1b_0
- freetype=2.12.1=ha860e81_0
- - holoviews=1.19.1=py311haa95532_0
- - hvplot=0.10.0=py311haa95532_0
+ - holoviews=1.20.0=py311haa95532_0
+ - hvplot=0.11.2=py311haa95532_0
- idna=3.7=py311haa95532_0
- intel-openmp=2023.1.0=h59b6b97_46320
- - ipykernel=6.28.0=py311haa95532_0
- - ipython=8.25.0=py311haa95532_0
- - jedi=0.19.1=py311haa95532_0
- - jinja2=3.1.4=py311haa95532_0
- - jpeg=9e=h2bbff1b_1
+ - ipykernel=6.29.5=py311haa95532_0
+ - ipython=8.30.0=py311haa95532_0
+ - jedi=0.19.2=py311haa95532_0
+ - jinja2=3.1.4=py311haa95532_1
+ - jpeg=9e=h827c3e9_3
- jsonschema-specifications=2023.7.1=py311haa95532_0
- - jsonschema=4.19.2=py311haa95532_0
+ - jsonschema=4.23.0=py311haa95532_0
- jupyter_client=7.4.9=py311haa95532_0
- jupyter_core=5.7.2=py311haa95532_0
- jupyter_events=0.10.0=py311haa95532_0
@@ -493,74 +496,75 @@ env_specs:
- jupyter_server_terminals=0.4.4=py311haa95532_1
- jupyterlab_pygments=0.2.2=py311haa95532_0
- kiwisolver=1.4.4=py311hd77b12b_0
- - lcms2=2.12=h83e58a3_0
- - lerc=3.0=hd77b12b_0
- - libbrotlicommon=1.0.9=h2bbff1b_8
- - libbrotlidec=1.0.9=h2bbff1b_8
- - libbrotlienc=1.0.9=h2bbff1b_8
- - libdeflate=1.17=h2bbff1b_1
+ - lcms2=2.16=hb4a4139_0
+ - lerc=4.0.0=h5da7b33_0
+ - libbrotlicommon=1.0.9=h827c3e9_9
+ - libbrotlidec=1.0.9=h827c3e9_9
+ - libbrotlienc=1.0.9=h827c3e9_9
+ - libdeflate=1.22=h5bf469e_0
- libffi=3.4.4=hd77b12b_1
- 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
+ - libtiff=4.5.1=h44ae7cf_1
+ - libwebp-base=1.3.2=h3d04722_1
- linkify-it-py=2.0.0=py311haa95532_0
- lz4-c=1.9.4=h2bbff1b_1
- markdown-it-py=2.2.0=py311haa95532_1
- markdown=3.4.1=py311haa95532_0
- - markupsafe=2.1.3=py311h2bbff1b_0
- - matplotlib-base=3.8.4=py311hf62ec03_0
+ - markupsafe=2.1.3=py311h827c3e9_1
+ - matplotlib-base=3.10.0=py311he19b0ae_0
- matplotlib-inline=0.1.6=py311haa95532_0
- mdit-py-plugins=0.3.0=py311haa95532_0
- mdurl=0.1.0=py311haa95532_0
- mistune=2.0.4=py311haa95532_0
- - mkl-service=2.4.0=py311h2bbff1b_1
+ - mkl-service=2.4.0=py311h827c3e9_2
- mkl=2023.1.0=h6b88ed4_46358
- - mkl_fft=1.3.8=py311h2bbff1b_0
- - mkl_random=1.2.4=py311h59b6b97_0
+ - mkl_fft=1.3.11=py311h827c3e9_0
+ - mkl_random=1.2.8=py311hea22821_0
- nbclassic=1.1.0=py311haa95532_0
- nbclient=0.8.0=py311haa95532_0
- - nbconvert=7.10.0=py311haa95532_0
- - nbformat=5.9.2=py311haa95532_0
+ - nbconvert=7.16.4=py311haa95532_0
+ - nbformat=5.10.4=py311haa95532_0
- nest-asyncio=1.6.0=py311haa95532_0
- notebook-shim=0.2.3=py311haa95532_0
- notebook=6.5.7=py311haa95532_0
- - numexpr=2.8.7=py311h1fcbade_0
- - numpy-base=1.26.4=py311hd01c5d8_0
- - numpy=1.26.4=py311hdab7c0b_0
- - openjpeg=2.4.0=h4afccc4_2
- - openssl=3.0.14=h827c3e9_0
+ - numexpr=2.10.1=py311h4cd664f_0
+ - numpy-base=2.2.1=py311hd01c5d8_0
+ - numpy=2.2.1=py311hdab7c0b_0
+ - openjpeg=2.5.2=hae555c5_0
+ - openssl=3.0.15=h827c3e9_0
- overrides=7.4.0=py311haa95532_0
- - packaging=24.1=py311haa95532_0
- - pandas=2.2.2=py311hea22821_0
- - panel=1.4.4=py311haa95532_0
- - param=2.1.1=py311haa95532_0
- - pillow=10.4.0=py311h827c3e9_0
- - pip=24.0=py311haa95532_0
+ - packaging=24.2=py311haa95532_0
+ - pandas=2.2.3=py311h5da7b33_0
+ - panel=1.5.3=py311haa95532_0
+ - param=2.2.0=py311haa95532_0
+ - parso=0.8.4=py311haa95532_0
+ - pillow=11.0.0=py311h096bfcc_1
+ - pip=24.2=py311haa95532_0
- platformdirs=3.10.0=py311haa95532_0
- - prometheus_client=0.14.1=py311haa95532_0
+ - prometheus_client=0.21.0=py311haa95532_0
- prompt-toolkit=3.0.43=py311haa95532_0
- - psutil=5.9.0=py311h2bbff1b_0
+ - psutil=5.9.0=py311h827c3e9_1
- pygments=2.15.1=py311haa95532_1
- - pyparsing=3.0.9=py311haa95532_0
+ - pyparsing=3.2.0=py311haa95532_0
- pysocks=1.7.1=py311haa95532_0
- python-dateutil=2.9.0post0=py311haa95532_2
- - python-fastjsonschema=2.16.2=py311haa95532_0
- - python-json-logger=2.0.7=py311haa95532_0
- - python=3.11.9=he1021f5_0
+ - python-fastjsonschema=2.20.0=py311haa95532_0
+ - python-json-logger=3.2.1=py311haa95532_0
+ - python=3.11.11=h4607a30_0
- pytz=2024.1=py311haa95532_0
- pyviz_comms=3.0.2=py311haa95532_0
- - pywin32=305=py311h2bbff1b_0
- - pywinpty=2.0.10=py311h5da7b33_0
- - pyyaml=6.0.1=py311h2bbff1b_0
+ - pywin32=308=py311h5da7b33_0
+ - pywinpty=2.0.14=py311h72d21ff_0
+ - pyyaml=6.0.2=py311h827c3e9_0
- pyzmq=24.0.1=py311h2bbff1b_0
- referencing=0.30.2=py311haa95532_0
- - requests=2.32.2=py311haa95532_0
+ - requests=2.32.3=py311haa95532_1
- rfc3339-validator=0.1.4=py311haa95532_0
- rfc3986-validator=0.1.1=py311haa95532_0
- - rpds-py=0.10.6=py311h062c2fa_0
+ - rpds-py=0.10.6=py311h636fa0f_1
- send2trash=1.8.2=py311haa95532_0
- - setuptools=69.5.1=py311haa95532_0
+ - setuptools=72.1.0=py311haa95532_0
- sniffio=1.3.0=py311haa95532_0
- soupsieve=2.5=py311haa95532_0
- sqlite=3.45.3=h2bbff1b_0
@@ -568,19 +572,19 @@ env_specs:
- terminado=0.17.1=py311haa95532_0
- tinycss2=1.2.1=py311haa95532_0
- tk=8.6.14=h0416ee5_0
- - tornado=6.4.1=py311h827c3e9_0
- - tqdm=4.66.4=py311h746a85d_0
+ - tornado=6.4.2=py311h827c3e9_0
+ - tqdm=4.66.5=py311h746a85d_0
- traitlets=5.14.3=py311haa95532_0
- - typing-extensions=4.11.0=py311haa95532_0
- - typing_extensions=4.11.0=py311haa95532_0
+ - typing-extensions=4.12.2=py311haa95532_0
+ - typing_extensions=4.12.2=py311haa95532_0
- uc-micro-py=1.0.1=py311haa95532_0
- unicodedata2=15.1.0=py311h2bbff1b_0
- - urllib3=2.2.2=py311haa95532_0
- - vc=14.2=h2eaa2aa_4
- - vs2015_runtime=14.29.30133=h43f2093_4
+ - urllib3=2.2.3=py311haa95532_0
+ - vc=14.40=haa95532_2
+ - vs2015_runtime=14.42.34433=h9531ae6_2
- webencodings=0.5.1=py311haa95532_1
- websocket-client=1.8.0=py311haa95532_0
- - wheel=0.43.0=py311haa95532_0
+ - wheel=0.44.0=py311haa95532_0
- win_inet_pton=1.1.0=py311haa95532_0
- winpty=0.4.3=4
- xyzservices=2022.9.0=py311haa95532_1
@@ -588,4 +592,4 @@ env_specs:
- yaml=0.2.5=he774522_0
- zeromq=4.3.5=hd77b12b_0
- zlib=1.2.13=h8cc25b3_1
- - zstd=1.5.5=hd43e919_2
+ - zstd=1.5.6=h8880b57_0
diff --git a/world_cup/anaconda-project.yml b/world_cup/anaconda-project.yml
index a295562ba..361c720d3 100644
--- a/world_cup/anaconda-project.yml
+++ b/world_cup/anaconda-project.yml
@@ -23,11 +23,11 @@ channels: [defaults]
packages: &pkgs
- notebook<7
- python=3.11
-- panel>=1.4.2
-- hvplot>=0.10.0
-- holoviews>=1.19
+- panel>=1.5.3
+- hvplot>=0.11.2
+- holoviews>=1.20.0
- numpy>=1.26.4
-- pandas>=2.2.1
+- pandas>=2.2.2
dependencies: *pkgs
diff --git a/world_cup/world_cup.ipynb b/world_cup/world_cup.ipynb
index 852fa83ae..4d875d931 100644
--- a/world_cup/world_cup.ipynb
+++ b/world_cup/world_cup.ipynb
@@ -40,7 +40,7 @@
"from holoviews import opts\n",
"import panel as pn\n",
"\n",
- "pn.extension()"
+ "pn.extension(sizing_mode='stretch_width')"
]
},
{
@@ -142,7 +142,7 @@
"\n",
"pitch_plot_height = 550\n",
"pitch_plot_width = 800\n",
- " \n",
+ "\n",
"# Helper function to create arcs\n",
"def create_arc(center, radius, start_angle, end_angle, clockwise=False):\n",
" if clockwise:\n",
@@ -181,7 +181,7 @@
" hv.Arrow(20, 5, '', '>', ), # attack arrow\n",
" hv.Text(10, 6, 'Attack', 11) # attack text\n",
" ]\n",
- " \n",
+ "\n",
" field = hv.Overlay(pitch_elements).opts(\n",
" frame_width=pitch_plot_width, frame_height=pitch_plot_height,\n",
" xlim=(-5, field_length + 5), ylim=(-5, field_width + 5),\n",
@@ -260,7 +260,7 @@
"def plot_event_heatmap(events_df, event_type, cmap='Greens'):\n",
" \"\"\"\n",
" Plots a heatmap of the specified event type on a football pitch.\n",
- " \n",
+ "\n",
" Parameters:\n",
" events_df (pd.DataFrame): The dataframe containing event data with the following columns:\n",
" - eventId: The identifier of the event's type.\n",
@@ -277,7 +277,7 @@
" - teamId: The identifier of the player's team.\n",
" event_type (str): The type of event to plot from the eventName column.\n",
" cmap (str): The color map to use for the heatmap. Default is 'Greens'.\n",
- " \n",
+ "\n",
" Returns:\n",
" hvPlot object: A heatmap plot of the specified event type overlaid on a football pitch.\n",
" \"\"\"\n",
@@ -285,11 +285,11 @@
" event = events_df[events_df['eventName'].str.lower() == event_type]\n",
" positions = [(pos[0]['x'], pos[0]['y']) for pos in event['positions'] if len(pos) > 0]\n",
" event_df = pd.DataFrame(positions, columns=['x', 'y'])\n",
- " pitch = plot_pitch() \n",
+ " pitch = plot_pitch()\n",
" title = f\"{event_type.capitalize()} Heatmap for All Players\"\n",
- " \n",
+ "\n",
" event_heatmap = event_df.hvplot.hexbin(x='x', y='y', cmap=cmap, min_count=1, title=title)\n",
- " \n",
+ "\n",
" event_heatmap_plot = (event_heatmap * pitch).opts(\n",
" frame_width=pitch_plot_width, frame_height=pitch_plot_height,\n",
" xlim=(-5, 110), ylim=(-5, 73), xaxis=None, yaxis=None\n",
@@ -382,11 +382,11 @@
" event_type = event_type.lower()\n",
" event = events_df[events_df['eventName'].str.lower() == event_type]\n",
" event_counts = event.groupby('playerId').size().reset_index(name=f'{event_type} count')\n",
- " \n",
+ "\n",
" top_players = event_counts.sort_values(by=f'{event_type} count', ascending=False).head(top_n)\n",
" top_players = top_players.merge(players_df, left_on='playerId', right_on='wyId')\n",
" top_players.set_index('playerId', inplace=True)\n",
- " \n",
+ "\n",
" return top_players[['shortName', f'{event_type} count']]"
]
},
@@ -444,7 +444,7 @@
"\n",
" bar_plot = top_players.hvplot.bar(\n",
" title=title, x='shortName', y=f'{event_type} count',\n",
- " xlabel='', ylabel=f'Number of {event_type}', rot=45\n",
+ " xlabel='', ylabel=f'Number of {event_type}', rot=45, color='#177F3B'\n",
" )\n",
"\n",
" return bar_plot"
@@ -507,40 +507,40 @@
"def plot_player_events(events_df, players_df, player_name):\n",
" \"\"\"\n",
" Plots a distribution of events performed by a specific player on a football pitch.\n",
- " \n",
+ "\n",
" Parameters:\n",
" events_df (pd.DataFrame): The dataframe containing event data.\n",
" players_df (pd.DataFrame): The dataframe containing player data.\n",
" player_name (str): The name of the player to plot events for.\n",
- " \n",
+ "\n",
" Returns:\n",
" hvPlot object: A scatter plot of the player's events overlaid on a football pitch.\n",
" \"\"\"\n",
" pitch = plot_pitch()\n",
" if not player_name:\n",
" return pn.Column(pn.pane.Markdown(\"## Start typing a player name above.\"), pitch)\n",
- " \n",
+ "\n",
" player_id = get_player_id(player_name)\n",
" if player_id is None:\n",
" return pn.Column(pn.pane.Markdown(\"## Please select a valid player.\"), pitch)\n",
- " \n",
+ "\n",
" player_events = events_df[events_df['playerId'] == player_id]\n",
- " \n",
+ "\n",
" if player_events.empty:\n",
" return pn.Column(pn.pane.Markdown(f\"## No events found for {player_name}.\"), pitch)\n",
- " \n",
+ "\n",
" positions = [(pos[0]['x'], pos[0]['y'], event) \n",
" for pos, event in zip(player_events['positions'], player_events['eventName']) \n",
" if len(pos) > 0]\n",
" event_df = pd.DataFrame(positions, columns=['x', 'y', 'eventName'])\n",
- " \n",
+ "\n",
" event_scatter = event_df.hvplot.points(x='x', y='y', c='eventName', cmap='Category20',\n",
" title=f'All Events for Player: {player_name}')\n",
- " \n",
+ "\n",
" player_scatter = (event_scatter * pitch).opts(frame_width=pitch_plot_width, frame_height=pitch_plot_height,\n",
" xlim=(-5, 110), ylim=(-5, 73),\n",
" xaxis=None, yaxis=None, legend_position='top')\n",
- " \n",
+ "\n",
" return player_scatter"
]
},
@@ -579,7 +579,7 @@
"player_events = pn.bind(plot_player_events, events_df=events_df,\n",
" players_df=players_df, player_name=player_name_selector)\n",
"\n",
- "pn.Column(player_name_selector, player_events, sizing_mode='stretch_width')"
+ "pn.Column(player_name_selector, player_events)"
]
},
{
@@ -600,29 +600,29 @@
"def plot_player_pass_trajectory(events_df, players_df, player_name):\n",
" player_id = get_player_id(player_name)\n",
" pitch = plot_pitch()\n",
- " \n",
+ "\n",
" if player_id is None:\n",
" return pn.Column(pn.pane.Markdown(\"## Please select a valid player.\"), pitch)\n",
- " \n",
+ "\n",
" player_events = events_df[events_df['playerId'] == player_id]\n",
- " \n",
+ "\n",
" if player_events.empty:\n",
" return pn.Column(pn.pane.Markdown(f\"## No events found for {player_name}.\"), pitch)\n",
- " \n",
+ "\n",
" passes = player_events[player_events['eventName'].str.lower() == 'pass']\n",
- " \n",
+ "\n",
" if passes.empty:\n",
" return pn.Column(pn.pane.Markdown(f\"## No passes found for {player_name}.\"), pitch)\n",
- " \n",
+ "\n",
" pass_positions = [(pos[0]['x'], pos[0]['y']) for pos in passes['positions'] if len(pos) > 1]\n",
" pass_df = pd.DataFrame(pass_positions, columns=['x', 'y'])\n",
- " \n",
+ "\n",
" pass_scatter = pass_df.hvplot.points(\n",
" x='x', y='y', color='#1D78B4',\n",
" title=f\"Click for Pass Trajectories of {player_name}\"\n",
" )\n",
" total_passes = hv.Text(75, 70, f'Total number of passes: {len(pass_df)}', halign='center', fontsize=12)\n",
- " \n",
+ "\n",
" # Callback to filter passes based on click location\n",
" def filter_passes(x, y, radius=1.5):\n",
" filtered_passes = passes[\n",
@@ -631,24 +631,24 @@
" (passes['positions'].apply(lambda pos: pos[0]['y']) >= y - radius) & \n",
" (passes['positions'].apply(lambda pos: pos[0]['y']) <= y + radius)\n",
" ]\n",
- " \n",
+ "\n",
" if filtered_passes.empty:\n",
" return hv.Overlay()\n",
- " \n",
+ "\n",
" pass_lines = []\n",
" for pos in filtered_passes['positions']:\n",
" pass_lines.append(hv.Segments([(pos[0]['x'], pos[0]['y'], pos[1]['x'], pos[1]['y'])]).opts(\n",
" color='green', line_width=2, line_alpha=.5))\n",
" pass_lines_overlay = hv.Overlay(pass_lines)\n",
- " \n",
+ "\n",
" return pass_lines_overlay\n",
- " \n",
+ "\n",
" # Create a stream for handling clicks\n",
" stream = hv.streams.Tap(source=pass_scatter, x=52, y=34)\n",
" dynamic_pass_lines = hv.DynamicMap(lambda x, y: filter_passes(x, y), streams=[stream])\n",
"\n",
" dynamic_map = pitch * pass_scatter * total_passes * dynamic_pass_lines\n",
- " \n",
+ "\n",
" return dynamic_map.opts(frame_width=pitch_plot_width, frame_height=pitch_plot_height,\n",
" xlim=(-5, 110), ylim=(-5, 73),\n",
" xaxis=None, yaxis=None)"
@@ -701,15 +701,17 @@
"outputs": [],
"source": [
"all_players_tab = pn.Column(\n",
- " pn.WidgetBox(event_type_selector, top_n_selector),\n",
+ " pn.Row(event_type_selector, top_n_selector),\n",
" bar_chart,\n",
" event_heatmap,\n",
+ " sizing_mode='stretch_both',\n",
")\n",
"\n",
"player_event_tab = pn.Column(\n",
" player_name_selector,\n",
" player_events,\n",
" player_pass_scatter,\n",
+ " sizing_mode='stretch_both',\n",
")\n",
"\n",
"layout = pn.Tabs(('All Players', all_players_tab), ('Per Player', player_event_tab))\n",
@@ -733,15 +735,17 @@
"metadata": {},
"outputs": [],
"source": [
- "logo = ''\n",
+ "logo = ''\n",
"\n",
- "text = \"\"\" ## Explore the 2018 FIFA World Cup with interactive visualizations built with `hvPlot` and `Panel` from HoloViz.\"\"\"\n",
+ "text = \"\"\" Explore the 2018 FIFA World Cup with interactive visualizations built with `hvPlot` and `Panel` from [HoloViz](https://holoviz.org/).\"\"\"\n",
"\n",
"template = pn.template.FastListTemplate(\n",
- " header_background='#18BB12',\n",
+ " header_background= '#177F3B',\n",
" title='2018 FIFA World Cup Dashboard',\n",
" sidebar=[logo, text],\n",
- " main=[layout]\n",
+ " main=[layout],\n",
+ " main_layout=None,\n",
+ " main_max_width=\"800px\",\n",
")\n",
"template.servable();"
]
@@ -771,7 +775,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.11.9"
+ "version": "3.11.11"
}
},
"nbformat": 4,