diff --git a/v2/packages.md b/v2/packages.md
index 4320c60..b9d3e05 100644
--- a/v2/packages.md
+++ b/v2/packages.md
@@ -21,46 +21,27 @@ It comes pre-installed with a standard set of python packages.
 - [beautifulsoup4: 4.12.2](https://pypi.org/project/beautifulsoup4/4.12.2/)
 - [bleach: 6.1.0](https://pypi.org/project/bleach/6.1.0/)
 - [build: 1.0.3](https://pypi.org/project/build/1.0.3/)
-- [cachetools: 5.3.2](https://pypi.org/project/cachetools/5.3.2/)
 - [cairocffi: 1.6.1](https://pypi.org/project/cairocffi/1.6.1/)
 - [cairosvg: 2.7.1](https://pypi.org/project/cairosvg/2.7.1/)
 - [certifi: 2023.11.17](https://pypi.org/project/certifi/2023.11.17/)
 - [cffi: 1.16.0](https://pypi.org/project/cffi/1.16.0/)
 - [charset-normalizer: 3.3.2](https://pypi.org/project/charset-normalizer/3.3.2/)
 - [click: 8.1.7](https://pypi.org/project/click/8.1.7/)
-- [click-plugins: 1.1.1](https://pypi.org/project/click-plugins/1.1.1/)
-- [cligj: 0.7.2](https://pypi.org/project/cligj/0.7.2/)
 - [comm: 0.2.0](https://pypi.org/project/comm/0.2.0/)
 - [contourpy: 1.2.0](https://pypi.org/project/contourpy/1.2.0/)
 - [coverage: 7.3.2](https://pypi.org/project/coverage/7.3.2/)
 - [cssselect2: 0.7.0](https://pypi.org/project/cssselect2/0.7.0/)
 - [cycler: 0.12.1](https://pypi.org/project/cycler/0.12.1/)
-- [db-dtypes: 1.1.1](https://pypi.org/project/db-dtypes/1.1.1/)
 - [debugpy: 1.8.0](https://pypi.org/project/debugpy/1.8.0/)
 - [decorator: 5.1.1](https://pypi.org/project/decorator/5.1.1/)
 - [defusedxml: 0.7.1](https://pypi.org/project/defusedxml/0.7.1/)
-- [descartes: 1.1.0](https://pypi.org/project/descartes/1.1.0/)
-- [ebmdatalab: 0.0.30](https://pypi.org/project/ebmdatalab/0.0.30/)
 - [exceptiongroup: 1.2.0](https://pypi.org/project/exceptiongroup/1.2.0/)
 - [executing: 2.0.1](https://pypi.org/project/executing/2.0.1/)
 - [fastjsonschema: 2.19.0](https://pypi.org/project/fastjsonschema/2.19.0/)
-- [fiona: 1.9.5](https://pypi.org/project/fiona/1.9.5/)
 - [fonttools: 4.46.0](https://pypi.org/project/fonttools/4.46.0/)
 - [formulaic: 0.6.6](https://pypi.org/project/formulaic/0.6.6/)
 - [fqdn: 1.5.1](https://pypi.org/project/fqdn/1.5.1/)
 - [future: 0.18.3](https://pypi.org/project/future/0.18.3/)
-- [geopandas: 0.14.1](https://pypi.org/project/geopandas/0.14.1/)
-- [google-api-core[grpc]: 2.14.0](https://pypi.org/project/google-api-core/2.14.0/)
-- [google-auth: 2.24.0](https://pypi.org/project/google-auth/2.24.0/)
-- [google-auth-oauthlib: 1.1.0](https://pypi.org/project/google-auth-oauthlib/1.1.0/)
-- [google-cloud-bigquery: 3.13.0](https://pypi.org/project/google-cloud-bigquery/3.13.0/)
-- [google-cloud-bigquery-storage: 2.23.0](https://pypi.org/project/google-cloud-bigquery-storage/2.23.0/)
-- [google-cloud-core: 2.3.3](https://pypi.org/project/google-cloud-core/2.3.3/)
-- [google-crc32c: 1.5.0](https://pypi.org/project/google-crc32c/1.5.0/)
-- [google-resumable-media: 2.6.0](https://pypi.org/project/google-resumable-media/2.6.0/)
-- [googleapis-common-protos: 1.61.0](https://pypi.org/project/googleapis-common-protos/1.61.0/)
-- [grpcio: 1.59.3](https://pypi.org/project/grpcio/1.59.3/)
-- [grpcio-status: 1.59.3](https://pypi.org/project/grpcio-status/1.59.3/)
 - [idna: 3.6](https://pypi.org/project/idna/3.6/)
 - [iniconfig: 2.0.0](https://pypi.org/project/iniconfig/2.0.0/)
 - [interface-meta: 1.3.0](https://pypi.org/project/interface-meta/1.3.0/)
@@ -75,7 +56,6 @@ It comes pre-installed with a standard set of python packages.
 - [jsonpointer: 2.4](https://pypi.org/project/jsonpointer/2.4/)
 - [jsonschema[format-nongpl]: 4.20.0](https://pypi.org/project/jsonschema/4.20.0/)
 - [jsonschema-specifications: 2023.11.2](https://pypi.org/project/jsonschema-specifications/2023.11.2/)
-- [jupyter: 1.0.0](https://pypi.org/project/jupyter/1.0.0/)
 - [jupyter-client: 8.6.0](https://pypi.org/project/jupyter-client/8.6.0/)
 - [jupyter-console: 6.6.3](https://pypi.org/project/jupyter-console/6.6.3/)
 - [jupyter-core: 5.5.0](https://pypi.org/project/jupyter-core/5.5.0/)
@@ -109,16 +89,13 @@ It comes pre-installed with a standard set of python packages.
 - [notebook-shim: 0.2.3](https://pypi.org/project/notebook-shim/0.2.3/)
 - [numba: 0.58.1](https://pypi.org/project/numba/0.58.1/)
 - [numpy: 1.26.2](https://pypi.org/project/numpy/1.26.2/)
-- [oauthlib: 3.2.2](https://pypi.org/project/oauthlib/3.2.2/)
 - [opensafely-cohort-extractor: 1.90.0](https://pypi.org/project/opensafely-cohort-extractor/1.90.0/)
 - [opensafely-matching: 0.2.0](https://pypi.org/project/opensafely-matching/0.2.0/)
 - [overrides: 7.4.0](https://pypi.org/project/overrides/7.4.0/)
 - [packaging: 23.2](https://pypi.org/project/packaging/23.2/)
 - [pandas: 2.1.3](https://pypi.org/project/pandas/2.1.3/)
-- [pandas-gbq: 0.19.2](https://pypi.org/project/pandas-gbq/0.19.2/)
 - [pandocfilters: 1.5.0](https://pypi.org/project/pandocfilters/1.5.0/)
 - [parso: 0.8.3](https://pypi.org/project/parso/0.8.3/)
-- [patsy: 0.5.4](https://pypi.org/project/patsy/0.5.4/)
 - [pexpect: 4.9.0](https://pypi.org/project/pexpect/4.9.0/)
 - [pillow: 10.1.0](https://pypi.org/project/pillow/10.1.0/)
 - [pip-tools: 7.3.0](https://pypi.org/project/pip-tools/7.3.0/)
@@ -127,20 +104,14 @@ It comes pre-installed with a standard set of python packages.
 - [pluggy: 1.3.0](https://pypi.org/project/pluggy/1.3.0/)
 - [prometheus-client: 0.19.0](https://pypi.org/project/prometheus-client/0.19.0/)
 - [prompt-toolkit: 3.0.41](https://pypi.org/project/prompt-toolkit/3.0.41/)
-- [proto-plus: 1.22.3](https://pypi.org/project/proto-plus/1.22.3/)
-- [protobuf: 4.25.1](https://pypi.org/project/protobuf/4.25.1/)
 - [psutil: 5.9.6](https://pypi.org/project/psutil/5.9.6/)
 - [ptyprocess: 0.7.0](https://pypi.org/project/ptyprocess/0.7.0/)
 - [pure-eval: 0.2.2](https://pypi.org/project/pure-eval/0.2.2/)
 - [py: 1.11.0](https://pypi.org/project/py/1.11.0/)
 - [pyarrow: 14.0.1](https://pypi.org/project/pyarrow/14.0.1/)
-- [pyasn1: 0.5.1](https://pypi.org/project/pyasn1/0.5.1/)
-- [pyasn1-modules: 0.3.0](https://pypi.org/project/pyasn1-modules/0.3.0/)
 - [pycparser: 2.21](https://pypi.org/project/pycparser/2.21/)
-- [pydata-google-auth: 1.8.2](https://pypi.org/project/pydata-google-auth/1.8.2/)
 - [pygments: 2.17.2](https://pypi.org/project/pygments/2.17.2/)
 - [pyparsing: 3.1.1](https://pypi.org/project/pyparsing/3.1.1/)
-- [pyproj: 3.6.1](https://pypi.org/project/pyproj/3.6.1/)
 - [pyproject-hooks: 1.0.0](https://pypi.org/project/pyproject-hooks/1.0.0/)
 - [pytest: 7.4.3](https://pypi.org/project/pytest/7.4.3/)
 - [python-dateutil: 2.8.2](https://pypi.org/project/python-dateutil/2.8.2/)
@@ -148,27 +119,21 @@ It comes pre-installed with a standard set of python packages.
 - [pytz: 2023.3.post1](https://pypi.org/project/pytz/2023.3.post1/)
 - [pyyaml: 6.0.1](https://pypi.org/project/pyyaml/6.0.1/)
 - [pyzmq: 25.1.2](https://pypi.org/project/pyzmq/25.1.2/)
-- [qtconsole: 5.5.1](https://pypi.org/project/qtconsole/5.5.1/)
-- [qtpy: 2.4.1](https://pypi.org/project/qtpy/2.4.1/)
 - [referencing: 0.31.1](https://pypi.org/project/referencing/0.31.1/)
 - [requests: 2.31.0](https://pypi.org/project/requests/2.31.0/)
-- [requests-oauthlib: 1.3.1](https://pypi.org/project/requests-oauthlib/1.3.1/)
 - [retry: 0.9.2](https://pypi.org/project/retry/0.9.2/)
 - [rfc3339-validator: 0.1.4](https://pypi.org/project/rfc3339-validator/0.1.4/)
 - [rfc3986-validator: 0.1.1](https://pypi.org/project/rfc3986-validator/0.1.1/)
 - [rpds-py: 0.13.2](https://pypi.org/project/rpds-py/0.13.2/)
-- [rsa: 4.9](https://pypi.org/project/rsa/4.9/)
 - [scikit-learn: 1.3.2](https://pypi.org/project/scikit-learn/1.3.2/)
 - [scipy: 1.11.4](https://pypi.org/project/scipy/1.11.4/)
 - [seaborn: 0.13.0](https://pypi.org/project/seaborn/0.13.0/)
 - [send2trash: 1.8.2](https://pypi.org/project/send2trash/1.8.2/)
-- [shapely: 2.0.2](https://pypi.org/project/shapely/2.0.2/)
 - [six: 1.16.0](https://pypi.org/project/six/1.16.0/)
 - [sniffio: 1.3.0](https://pypi.org/project/sniffio/1.3.0/)
 - [soupsieve: 2.5](https://pypi.org/project/soupsieve/2.5/)
 - [sqlparse: 0.4.4](https://pypi.org/project/sqlparse/0.4.4/)
 - [stack-data: 0.6.3](https://pypi.org/project/stack-data/0.6.3/)
-- [statsmodels: 0.14.0](https://pypi.org/project/statsmodels/0.14.0/)
 - [structlog: 23.2.0](https://pypi.org/project/structlog/23.2.0/)
 - [tabulate: 0.9.0](https://pypi.org/project/tabulate/0.9.0/)
 - [tenacity: 8.2.3](https://pypi.org/project/tenacity/8.2.3/)
diff --git a/v2/requirements.in b/v2/requirements.in
index a89dd8b..82a8776 100644
--- a/v2/requirements.in
+++ b/v2/requirements.in
@@ -1,7 +1,8 @@
 # Basic requirements for notebook infrastructure provided in base
 # docker image
 pip-tools
-jupyter
+notebook
+jupyter-console
 jupyterlab
 jupytext
 bash_kernel
@@ -9,10 +10,8 @@ nbval
 opensafely-matching
 
 # Commonly-used packages provided in base docker image
-pandas-gbq
 pandas
 numpy
-ebmdatalab
 matplotlib
 scipy
 tqdm
diff --git a/v2/requirements.txt b/v2/requirements.txt
index 25c762f..cf29f44 100644
--- a/v2/requirements.txt
+++ b/v2/requirements.txt
@@ -20,7 +20,6 @@ async-lru==2.0.4
     # via jupyterlab
 attrs==23.1.0
     # via
-    #   fiona
     #   jsonschema
     #   referencing
 autograd==1.6.2
@@ -39,17 +38,12 @@ bleach==6.1.0
     # via nbconvert
 build==1.0.3
     # via pip-tools
-cachetools==5.3.2
-    # via google-auth
 cairocffi==1.6.1
     # via cairosvg
 cairosvg==2.7.1
     # via -r v2/requirements.in
 certifi==2023.11.17
-    # via
-    #   fiona
-    #   pyproj
-    #   requests
+    # via requests
 cffi==1.16.0
     # via
     #   argon2-cffi-bindings
@@ -57,15 +51,7 @@ cffi==1.16.0
 charset-normalizer==3.3.2
     # via requests
 click==8.1.7
-    # via
-    #   click-plugins
-    #   cligj
-    #   fiona
-    #   pip-tools
-click-plugins==1.1.1
-    # via fiona
-cligj==0.7.2
-    # via fiona
+    # via pip-tools
 comm==0.2.0
     # via
     #   ipykernel
@@ -78,8 +64,6 @@ cssselect2==0.7.0
     # via cairosvg
 cycler==0.12.1
     # via matplotlib
-db-dtypes==1.1.1
-    # via pandas-gbq
 debugpy==1.8.0
     # via ipykernel
 decorator==5.1.1
@@ -90,10 +74,6 @@ defusedxml==0.7.1
     # via
     #   cairosvg
     #   nbconvert
-descartes==1.1.0
-    # via ebmdatalab
-ebmdatalab==0.0.30
-    # via -r v2/requirements.in
 exceptiongroup==1.2.0
     # via
     #   anyio
@@ -103,8 +83,6 @@ executing==2.0.1
     # via stack-data
 fastjsonschema==2.19.0
     # via nbformat
-fiona==1.9.5
-    # via geopandas
 fonttools==4.46.0
     # via matplotlib
 formulaic==0.6.6
@@ -113,46 +91,6 @@ fqdn==1.5.1
     # via jsonschema
 future==0.18.3
     # via autograd
-geopandas==0.14.1
-    # via ebmdatalab
-google-api-core[grpc]==2.14.0
-    # via
-    #   google-cloud-bigquery
-    #   google-cloud-bigquery-storage
-    #   google-cloud-core
-    #   pandas-gbq
-google-auth==2.24.0
-    # via
-    #   google-api-core
-    #   google-auth-oauthlib
-    #   google-cloud-core
-    #   pandas-gbq
-    #   pydata-google-auth
-google-auth-oauthlib==1.1.0
-    # via
-    #   pandas-gbq
-    #   pydata-google-auth
-google-cloud-bigquery==3.13.0
-    # via pandas-gbq
-google-cloud-bigquery-storage==2.23.0
-    # via pandas-gbq
-google-cloud-core==2.3.3
-    # via google-cloud-bigquery
-google-crc32c==1.5.0
-    # via google-resumable-media
-google-resumable-media==2.6.0
-    # via google-cloud-bigquery
-googleapis-common-protos==1.61.0
-    # via
-    #   google-api-core
-    #   grpcio-status
-grpcio==1.59.3
-    # via
-    #   google-api-core
-    #   google-cloud-bigquery
-    #   grpcio-status
-grpcio-status==1.59.3
-    # via google-api-core
 idna==3.6
     # via
     #   anyio
@@ -165,20 +103,16 @@ interface-meta==1.3.0
 ipykernel==6.27.1
     # via
     #   bash-kernel
-    #   jupyter
     #   jupyter-console
     #   jupyterlab
     #   nbval
-    #   qtconsole
 ipython==8.18.1
     # via
     #   ipykernel
     #   ipywidgets
     #   jupyter-console
 ipywidgets==8.1.1
-    # via
-    #   -r v2/requirements.in
-    #   jupyter
+    # via -r v2/requirements.in
 isoduration==20.11.0
     # via jsonschema
 jedi==0.19.1
@@ -202,8 +136,6 @@ jsonschema[format-nongpl]==4.20.0
     #   nbformat
 jsonschema-specifications==2023.11.2
     # via jsonschema
-jupyter==1.0.0
-    # via -r v2/requirements.in
 jupyter-client==8.6.0
     # via
     #   ipykernel
@@ -211,9 +143,8 @@ jupyter-client==8.6.0
     #   jupyter-server
     #   nbclient
     #   nbval
-    #   qtconsole
 jupyter-console==6.6.3
-    # via jupyter
+    # via -r v2/requirements.in
 jupyter-core==5.5.0
     # via
     #   ipykernel
@@ -224,7 +155,6 @@ jupyter-core==5.5.0
     #   nbclient
     #   nbconvert
     #   nbformat
-    #   qtconsole
 jupyter-events==0.9.0
     # via jupyter-server
 jupyter-lsp==2.2.1
@@ -273,7 +203,6 @@ markupsafe==2.1.3
 matplotlib==3.8.2
     # via
     #   -r v2/requirements.in
-    #   descartes
     #   lifelines
     #   seaborn
     #   upsetplot
@@ -291,9 +220,7 @@ mistune==3.0.2
 nbclient==0.9.0
     # via nbconvert
 nbconvert==7.12.0
-    # via
-    #   jupyter
-    #   jupyter-server
+    # via jupyter-server
 nbformat==5.9.2
     # via
     #   jupyter-server
@@ -306,7 +233,7 @@ nbval==0.10.0
 nest-asyncio==1.5.8
     # via ipykernel
 notebook==7.0.6
-    # via jupyter
+    # via -r v2/requirements.in
 notebook-shim==0.2.3
     # via
     #   jupyterlab
@@ -318,22 +245,15 @@ numpy==1.26.2
     #   -r v2/requirements.in
     #   autograd
     #   contourpy
-    #   db-dtypes
     #   formulaic
     #   lifelines
     #   matplotlib
     #   numba
     #   pandas
-    #   pandas-gbq
-    #   patsy
     #   pyarrow
     #   scikit-learn
     #   scipy
     #   seaborn
-    #   shapely
-    #   statsmodels
-oauthlib==3.2.2
-    # via requests-oauthlib
 opensafely-cohort-extractor==1.90.0
     # via -r v2/requirements.in
 opensafely-matching==0.2.0
@@ -343,9 +263,6 @@ overrides==7.4.0
 packaging==23.2
     # via
     #   build
-    #   db-dtypes
-    #   geopandas
-    #   google-cloud-bigquery
     #   ipykernel
     #   jupyter-server
     #   jupyterlab
@@ -355,33 +272,19 @@ packaging==23.2
     #   nbconvert
     #   plotly
     #   pytest
-    #   qtconsole
-    #   qtpy
-    #   statsmodels
 pandas==2.1.3
     # via
     #   -r v2/requirements.in
-    #   db-dtypes
-    #   ebmdatalab
     #   formulaic
-    #   geopandas
     #   lifelines
     #   opensafely-cohort-extractor
     #   opensafely-matching
-    #   pandas-gbq
     #   seaborn
-    #   statsmodels
     #   upsetplot
-pandas-gbq==0.19.2
-    # via
-    #   -r v2/requirements.in
-    #   ebmdatalab
 pandocfilters==1.5.0
     # via nbconvert
 parso==0.8.3
     # via jedi
-patsy==0.5.4
-    # via statsmodels
 pexpect==4.9.0
     # via
     #   bash-kernel
@@ -405,18 +308,6 @@ prompt-toolkit==3.0.41
     # via
     #   ipython
     #   jupyter-console
-proto-plus==1.22.3
-    # via
-    #   google-cloud-bigquery
-    #   google-cloud-bigquery-storage
-protobuf==4.25.1
-    # via
-    #   google-api-core
-    #   google-cloud-bigquery
-    #   google-cloud-bigquery-storage
-    #   googleapis-common-protos
-    #   grpcio-status
-    #   proto-plus
 psutil==5.9.6
     # via ipykernel
 ptyprocess==0.7.0
@@ -430,29 +321,16 @@ py==1.11.0
 pyarrow==14.0.1
     # via
     #   -r v2/requirements.in
-    #   db-dtypes
     #   opensafely-cohort-extractor
-    #   pandas-gbq
-pyasn1==0.5.1
-    # via
-    #   pyasn1-modules
-    #   rsa
-pyasn1-modules==0.3.0
-    # via google-auth
 pycparser==2.21
     # via cffi
-pydata-google-auth==1.8.2
-    # via pandas-gbq
 pygments==2.17.2
     # via
     #   ipython
     #   jupyter-console
     #   nbconvert
-    #   qtconsole
 pyparsing==3.1.1
     # via matplotlib
-pyproj==3.6.1
-    # via geopandas
 pyproject-hooks==1.0.0
     # via build
 pytest==7.4.3
@@ -462,7 +340,6 @@ pytest==7.4.3
 python-dateutil==2.8.2
     # via
     #   arrow
-    #   google-cloud-bigquery
     #   jupyter-client
     #   matplotlib
     #   pandas
@@ -481,11 +358,6 @@ pyzmq==25.1.2
     #   jupyter-client
     #   jupyter-console
     #   jupyter-server
-    #   qtconsole
-qtconsole==5.5.1
-    # via jupyter
-qtpy==2.4.1
-    # via qtconsole
 referencing==0.31.1
     # via
     #   jsonschema
@@ -493,13 +365,8 @@ referencing==0.31.1
     #   jupyter-events
 requests==2.31.0
     # via
-    #   google-api-core
-    #   google-cloud-bigquery
     #   jupyterlab-server
     #   opensafely-cohort-extractor
-    #   requests-oauthlib
-requests-oauthlib==1.3.1
-    # via google-auth-oauthlib
 retry==0.9.2
     # via opensafely-cohort-extractor
 rfc3339-validator==0.1.4
@@ -514,8 +381,6 @@ rpds-py==0.13.2
     # via
     #   jsonschema
     #   referencing
-rsa==4.9
-    # via google-auth
 scikit-learn==1.3.2
     # via -r v2/requirements.in
 scipy==1.11.4
@@ -525,21 +390,14 @@ scipy==1.11.4
     #   formulaic
     #   lifelines
     #   scikit-learn
-    #   statsmodels
 seaborn==0.13.0
-    # via
-    #   ebmdatalab
-    #   opensafely-cohort-extractor
+    # via opensafely-cohort-extractor
 send2trash==1.8.2
     # via jupyter-server
-shapely==2.0.2
-    # via geopandas
 six==1.16.0
     # via
     #   asttokens
     #   bleach
-    #   fiona
-    #   patsy
     #   python-dateutil
     #   rfc3339-validator
 sniffio==1.3.0
@@ -550,8 +408,6 @@ sqlparse==0.4.4
     # via opensafely-cohort-extractor
 stack-data==0.6.3
     # via ipython
-statsmodels==0.14.0
-    # via ebmdatalab
 structlog==23.2.0
     # via opensafely-cohort-extractor
 tabulate==0.9.0
@@ -604,7 +460,6 @@ traitlets==5.14.0
     #   nbclient
     #   nbconvert
     #   nbformat
-    #   qtconsole
 types-python-dateutil==2.8.19.14
     # via arrow
 typing-extensions==4.8.0