diff --git a/examples/toolbox-paper/1_preprocessing.py b/examples/toolbox-paper/1_preprocessing.py new file mode 100644 index 0000000..81605f5 --- /dev/null +++ b/examples/toolbox-paper/1_preprocessing.py @@ -0,0 +1,56 @@ +import os +from dask.distributed import Client + +import osl_ephys + + +if __name__ == "__main__": + client = Client(n_workers=16, threads_per_worker=1) # specify to enable parallel processing + basedir = "ds117" + + config = """ + meta: + event_codes: + famous/first: 5 + famous/immediate: 6 + famous/last: 7 + unfamiliar/first: 13 + unfamiliar/immediate: 14 + unfamiliar/last: 15 + scrambled/first: 17 + scrambled/immediate: 18 + scrambled/last: 19 + preproc: + - find_events: {min_duration: 0.005} + - set_channel_types: {EEG061: eog, EEG062: eog, EEG063: ecg} + - filter: {l_freq: 0.5, h_freq: 125, method: iir, iir_params: {order: 5, ftype: butter}} + - notch_filter: {freqs: 50 100} + - resample: {sfreq: 250} + - bad_segments: {segment_len: 500, picks: mag} + - bad_segments: {segment_len: 500, picks: grad} + - bad_segments: {segment_len: 500, picks: mag, mode: diff} + - bad_segments: {segment_len: 500, picks: grad, mode: diff} + - bad_channels: {picks: mag, significance_level: 0.1} + - bad_channels: {picks: grad, significance_level: 0.1} + - ica_raw: {picks: meg, n_components: 40} + - ica_autoreject: {picks: meg, ecgmethod: correlation, eogmethod: correlation, + eogthreshold: 0.35, apply: False} + - interpolate_bads: {reset_bads: False} + """ + + # Study utils enables selection of existing paths using various wild cards + study = osl_ephys.utils.Study(os.path.join(basedir, "sub{sub_id}/MEG/run_{run_id}_raw.fif")) + inputs = sorted(study.get()) + + # specify session names and output directory + subjects = [f"sub{i+1:03d}-run{j+1:02d}" for i in range(19) for j in range(6)] + outdir = os.path.join(basedir, "processed") + + osl_ephys.preprocessing.run_proc_batch( + config, + inputs, + subjects, + outdir, + dask_client=True, + random_seed=2280431064, + ) diff --git a/examples/toolbox-paper/2_source-reconstruct.py b/examples/toolbox-paper/2_source-reconstruct.py new file mode 100644 index 0000000..c85d1ef --- /dev/null +++ b/examples/toolbox-paper/2_source-reconstruct.py @@ -0,0 +1,68 @@ +import os +import numpy as np +from dask.distributed import Client +from osl_ephys import source_recon, utils + +source_recon.setup_fsl("~/fsl") # FSL needs to be installed + +def fix_headshape_points(outdir, subject): + filenames = source_recon.rhino.get_coreg_filenames(outdir, subject) + + # Load saved headshape and nasion files + hs = np.loadtxt(filenames["polhemus_headshape_file"]) + nas = np.loadtxt(filenames["polhemus_nasion_file"]) + lpa = np.loadtxt(filenames["polhemus_lpa_file"]) + rpa = np.loadtxt(filenames["polhemus_rpa_file"]) + + # Remove headshape points on the nose + remove = np.logical_and(hs[1] > max(lpa[1], rpa[1]), hs[2] < nas[2]) + hs = hs[:, ~remove] + + # Overwrite headshape file + utils.logger.log_or_print(f"overwritting {filenames['polhemus_headshape_file']}") + np.savetxt(filenames["polhemus_headshape_file"], hs) + +if __name__ == "__main__": + utils.logger.set_up(level="INFO") + client = Client(n_workers=16, threads_per_worker=1) + + config = """ + source_recon: + - extract_polhemus_from_info: {} + - fix_headshape_points: {} + - compute_surfaces: + include_nose: False + - coregister: + use_nose: False + use_headshape: True + - forward_model: + model: Single Layer + - beamform_and_parcellate: + freq_range: [1, 45] + chantypes: [mag, grad] + rank: {meg: 60} + parcellation_file: Glasser52_binary_space-MNI152NLin6_res-8x8x8.nii.gz + method: spatial_basis + orthogonalisation: symmetric + """ + + basedir = "ds117" + proc_dir = os.path.join(basedir, "processed") + + # Define inputs + subjects = [f"sub{i+1:03d}-run{j+1:02d}" for i in range(19) for j in range(6)] + preproc_files = sorted(utils.Study(os.path.join(proc_dir, "sub{sub_id}- run{run_id}/sub{sub_id}-run{run_id}_preproc-raw.fif")).get()) + smri_files = np.concatenate([[smri_file]*6 for smri_file in sorted(utils.Study(os.path.join(basedir, "sub{sub_id}/anatomy/highres001.nii.gz"))).get()]) + + # Run source batch + source_recon.run_src_batch( + config, + outdir=proc_dir, + subjects=subjects, + preproc_files=preproc_files, + smri_files=smri_files, + extra_funcs=[fix_headshape_points], + dask_client=True, + random_seed=1392754308, + ) + diff --git a/examples/toolbox-paper/3_sign-flip.py b/examples/toolbox-paper/3_sign-flip.py new file mode 100644 index 0000000..20e75d7 --- /dev/null +++ b/examples/toolbox-paper/3_sign-flip.py @@ -0,0 +1,46 @@ + +import os +from glob import glob +from dask.distributed import Client + +from osl_ephys import source_recon, utils + +source_recon.setup_fsl("~/fsl") + +# Directory containing source reconstructed data +proc_dir = "ds117/processed" +src_files = sorted(utils.Study(os.path.join(proc_dir, +"sub{sub_id}-run{run_id}/parc/parc-raw.fif")).get()) + +if __name__ == "__main__": + utils.logger.set_up(level="INFO") + + subjects = [f"sub{i+1:03d}-run{j+1:02d}" for i in range(19) for j in range(6)] + + # Find a good template subject to match others to + template = source_recon.find_template_subject( + proc_dir, subjects, n_embeddings=15, standardize=True, + ) + + # Settings + config = f""" + source_recon: + - fix_sign_ambiguity: + template: {template} + n_embeddings: 15 + standardize: True + n_init: 3 + n_iter: 3000 + max_flips: 20 + """ + + # Setup parallel processing + client = Client(n_workers=16, threads_per_worker=1) + + # Run sign flipping + source_recon.run_src_batch(config, proc_dir, subjects, dask_client=True, random_seed=3116145039) + + + + + diff --git a/examples/toolbox-paper/4_stats.py b/examples/toolbox-paper/4_stats.py new file mode 100644 index 0000000..9af0d95 --- /dev/null +++ b/examples/toolbox-paper/4_stats.py @@ -0,0 +1,46 @@ +import os +import numpy as np +import glmtools +import matplotlib.pyplot as plt +from dask.distributed import Client +from osl_ephys import preprocessing, glm + + +if __name__ == "__main__": + client = Client(n_workers=16, threads_per_worker=1) + + config = """ + preproc: + - read_dataset: {ftype: sflip_parc-raw} + - epochs: {picks: misc, tmin: -0.2, tmax: 0.3} + - glm_add_regressor: {name: famous, rtype: Categorical, codes: [5 6 7]} + - glm_add_regressor: {name: unfamiliar, rtype: Categorical, codes: [13 14 15]} + - glm_add_regressor: {name: scrambled, rtype: Categorical, codes: [17 18 19]} + - glm_add_contrast: {name: Mean, values: {famous: 1/3, unfamiliar: 1/3, scrambled: 1/3}} + - glm_add_contrast: {name: Faces-Scrambled, values: {famous: 1, unfamiliar: 1, scrambled: -2}} + - glm_fit: {target: epochs, method: glm_epochs} + group: + - glm_add_regressor: {name: Subject, rtype: Categorical, key: Subject, codes: unique} + - glm_add_contrast: {name: Mean, values: unique, key: Subject} + - glm_fit: {method: epochs, tmin: 0.05, tmax: 0.3} + - glm_permutations: {method: epochs, target: group_glm, contrast: Mean, type: max, nperms: 1000, threshold: 0.99} + """ + proc_dir = "ds117/processed" + src_files = sorted(utils.Study(os.path.join(proc_dir, +"sub{sub_id}-run{run_id}", "sub{sub_id}-run{run_id}_sflip_parc-raw.fif")).get()) + subjects = [f"sub{i+1:03d}-run{j+1:02d}" for i in range(19) for j in range(6)] + covs = [f"Subject": [sub.split("-")[0]for sub in subjects] + + preprocessing.run_proc_batch( + config, + src_files, + subjects, + outdir=proc_dir, + ftype='raw', + covs=covs, + dask_client=True, + overwrite=True, + gen_report=False, + skip_save=['events', 'raw', 'ica', 'event_id', 'sflip_parc-raw'], + ) + diff --git a/examples/toolbox-paper/README.md b/examples/toolbox-paper/README.md new file mode 100644 index 0000000..6ea7133 --- /dev/null +++ b/examples/toolbox-paper/README.md @@ -0,0 +1,22 @@ +# OSL Toolbox Paper + +The scripts for the toolbox paper can be found here in the order they appear in the manuscript. You can download the data from [OpenfMRI](https://openfmri.org/s3-browser/?prefix=ds000117/ds000117_R0.1.1/compressed/). Extract the `tar.gz` files in a folder called `ds117`. Note: you may have to change the base directory in the scripts to match the directory where you store the data. You also need to [install FSL](https://fsl.fmrib.ox.ac.uk/fsl/docs/#/install/index), and make sure that `source_recon.setup_fsl()` in `2_source-reconstruct.py` and `3_sign-flip.py` is pointing to the correct directory. + +If you wish to fully reproduce the analysis pipeline install the environment specified in `osl-toolbox-paper.yml`, and set `random_seed` in `run_proc_batch` and `run_src_batch` according to the seed found in the logfiles on [OSF](https://osf.io/2rnyg/). + +## Manual preprocessing + +Note that in the toolbox paper, automatically labeled ICA components were manually refined for the following sessions: +- sub008-ses03 +- sub019-ses01 +- sub019-ses02 +- sub019-ses03 +- sub019-ses04 +- sub019-ses05 +- sub019-ses06 +- sub010-ses05 + +This was done by running the following command line function iteratively, replacing "session". +`osl_ica_label None processed "session"` +After all specified sessions were refined, all automatically/manually labeled components were removed from the preprocessed MEG data using the command line call +`osl_ica_apply processed` \ No newline at end of file diff --git a/examples/toolbox-paper/osl-toolbox-paper.yml b/examples/toolbox-paper/osl-toolbox-paper.yml new file mode 100644 index 0000000..51dacff --- /dev/null +++ b/examples/toolbox-paper/osl-toolbox-paper.yml @@ -0,0 +1,366 @@ +name: osl-toolbox-paper +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1=conda_forge + - _openmp_mutex=4.5=2_gnu + - aom=3.5.0=h27087fc_0 + - brotli-python=1.1.0=py38h17151c0_1 + - bzip2=1.0.8=h4bc722e_7 + - c-ares=1.32.2=h4bc722e_0 + - ca-certificates=2024.7.4=hbcca054_0 + - certifi=2024.7.4=pyhd8ed1ab_0 + - cffi=1.16.0=py38h6d47a40_0 + - charset-normalizer=3.3.2=pyhd8ed1ab_0 + - curl=8.8.0=he654da7_1 + - double-conversion=3.2.0=h27087fc_1 + - eigen=3.4.0=h00ab1b0_0 + - elfutils=0.190=h924a536_1 + - expat=2.6.2=h59595ed_0 + - ffmpeg=4.4.2=gpl_h8dda1f0_112 + - font-ttf-dejavu-sans-mono=2.37=hab24e00_0 + - font-ttf-inconsolata=3.000=h77eed37_0 + - font-ttf-source-code-pro=2.038=h77eed37_0 + - font-ttf-ubuntu=0.83=h77eed37_2 + - fontconfig=2.14.2=h14ed4e7_0 + - fonts-conda-ecosystem=1=0 + - fonts-conda-forge=1=0 + - freetype=2.12.1=h267a509_2 + - gettext=0.22.5=h59595ed_2 + - gettext-tools=0.22.5=h59595ed_2 + - gl2ps=1.4.2=h0708190_0 + - gmp=6.3.0=hac33072_2 + - gnutls=3.7.9=hb077bed_0 + - h2=4.1.0=py38h578d9bd_0 + - hdf4=4.2.15=h9772cbc_5 + - hdf5=1.12.2=nompi_h4df4325_101 + - hpack=4.0.0=pyh9f0ad1d_0 + - hyperframe=6.0.1=pyhd8ed1ab_0 + - icu=73.2=h59595ed_0 + - idna=3.7=pyhd8ed1ab_0 + - imageio=2.34.2=pyh12aca89_0 + - jpeg=9e=h0b41bf4_3 + - jsoncpp=1.9.5=h4bd325d_1 + - keyutils=1.6.1=h166bdaf_0 + - krb5=1.21.3=h659f571_0 + - lame=3.100=h166bdaf_1003 + - lcms2=2.14=h6ed2654_0 + - ld_impl_linux-64=2.40=hf3520f5_7 + - lerc=4.0.0=h27087fc_0 + - libaec=1.1.3=h59595ed_0 + - libarchive=3.7.4=hfca40fe_0 + - libasprintf=0.22.5=h661eb56_2 + - libasprintf-devel=0.22.5=h661eb56_2 + - libblas=3.9.0=22_linux64_openblas + - libcblas=3.9.0=22_linux64_openblas + - libcurl=8.8.0=hca28451_1 + - libdeflate=1.14=h166bdaf_0 + - libdrm=2.4.122=h4ab18f5_0 + - libedit=3.1.20191231=he28a2e2_2 + - libev=4.33=hd590300_2 + - libexpat=2.6.2=h59595ed_0 + - libffi=3.4.2=h7f98852_5 + - libgcc-ng=14.1.0=h77fa898_0 + - libgettextpo=0.22.5=h59595ed_2 + - libgettextpo-devel=0.22.5=h59595ed_2 + - libgfortran-ng=14.1.0=h69a702a_0 + - libgfortran5=14.1.0=hc5f4f2c_0 + - libgomp=14.1.0=h77fa898_0 + - libhwloc=2.11.1=default_hecaa2ac_1000 + - libiconv=1.17=hd590300_2 + - libidn2=2.3.7=hd590300_0 + - liblapack=3.9.0=22_linux64_openblas + - libllvm16=16.0.6=hb3ce162_3 + - libmicrohttpd=1.0.1=h97afed2_0 + - libnetcdf=4.8.1=nompi_h261ec11_106 + - libnghttp2=1.58.0=h47da74e_1 + - libnsl=2.0.1=hd590300_0 + - libogg=1.3.5=h4ab18f5_0 + - libopenblas=0.3.27=pthreads_hac2b453_1 + - libpciaccess=0.18=hd590300_0 + - libpng=1.6.43=h2797004_0 + - libsqlite=3.46.0=hde9e2c9_0 + - libssh2=1.11.0=h0841786_0 + - libstdcxx-ng=14.1.0=hc0a3c3a_0 + - libtasn1=4.19.0=h166bdaf_0 + - libtheora=1.1.1=h4ab18f5_1006 + - libtiff=4.4.0=h82bc61c_5 + - libunistring=0.9.10=h7f98852_0 + - libuuid=2.38.1=h0b41bf4_0 + - libva=2.18.0=h0b41bf4_0 + - libvorbis=1.3.7=h9c3ff4c_0 + - libvpx=1.11.0=h9c3ff4c_3 + - libwebp-base=1.4.0=hd590300_0 + - libxcb=1.13=h7f98852_1004 + - libxml2=2.12.7=hc051c1a_1 + - libzip=1.10.1=h2629f0a_3 + - libzlib=1.2.13=h4ab18f5_6 + - loguru=0.7.2=py38h578d9bd_1 + - lz4-c=1.9.4=hcb278e6_0 + - lzo=2.10=hd590300_1001 + - mesalib=23.0.2=h3855f93_0 + - ncurses=6.5=h59595ed_0 + - nettle=3.9.1=h7ab15ed_0 + - openh264=2.3.1=hcb278e6_2 + - openjpeg=2.5.0=h7d73246_1 + - openssl=3.3.1=h4bc722e_2 + - p11-kit=0.24.1=hc5aa10d_0 + - packaging=24.1=pyhd8ed1ab_0 + - pillow=9.2.0=py38h9eb91d8_3 + - pip=23.3.1=pyhd8ed1ab_0 + - platformdirs=4.2.2=pyhd8ed1ab_0 + - pooch=1.8.2=pyhd8ed1ab_0 + - proj=9.0.1=h93bde94_1 + - pthread-stubs=0.4=h36c2ea0_1001 + - pugixml=1.11.4=h59595ed_1 + - pycparser=2.22=pyhd8ed1ab_0 + - pysocks=1.7.1=pyha2e5f31_6 + - python=3.8.16=he550d4f_1_cpython + - python_abi=3.8=4_cp38 + - pyvista=0.38.5=pyhd8ed1ab_0 + - readline=8.2=h8228510_1 + - requests=2.32.3=pyhd8ed1ab_0 + - scooby=0.10.0=pyhd8ed1ab_0 + - setuptools=71.0.4=pyhd8ed1ab_0 + - sqlite=3.46.0=h6d4b2fc_0 + - svt-av1=1.4.1=hcb278e6_0 + - tbb=2021.12.0=h434a139_3 + - tbb-devel=2021.12.0=hfcbfbdb_3 + - tk=8.6.13=noxft_h4845f30_101 + - typing_extensions=4.12.2=pyha770c72_0 + - urllib3=2.2.2=pyhd8ed1ab_1 + - utfcpp=4.0.5=ha770c72_0 + - vtk=9.1.0=osmesa_py38h68dc7f3_115 + - wheel=0.43.0=pyhd8ed1ab_1 + - x264=1!164.3095=h166bdaf_2 + - x265=3.5=h924138e_3 + - xorg-damageproto=1.2.1=h7f98852_1002 + - xorg-fixesproto=5.0=h7f98852_1002 + - xorg-glproto=1.4.17=h7f98852_1002 + - xorg-kbproto=1.0.7=h7f98852_1002 + - xorg-libice=1.0.10=h7f98852_0 + - xorg-libsm=1.2.3=hd9c2040_1000 + - xorg-libx11=1.8.4=h0b41bf4_0 + - xorg-libxau=1.0.11=hd590300_0 + - xorg-libxdamage=1.1.5=h7f98852_1 + - xorg-libxdmcp=1.1.3=h7f98852_0 + - xorg-libxext=1.3.4=h0b41bf4_2 + - xorg-libxfixes=5.0.3=h7f98852_1004 + - xorg-libxrandr=1.5.2=h7f98852_1 + - xorg-libxrender=0.9.10=h7f98852_1003 + - xorg-libxt=1.3.0=hd590300_0 + - xorg-randrproto=1.5.0=h7f98852_1001 + - xorg-renderproto=0.11.1=h7f98852_1002 + - xorg-util-macros=1.19.3=h7f98852_0 + - xorg-xextproto=7.3.0=h0b41bf4_1003 + - xorg-xf86vidmodeproto=2.3.1=h7f98852_1002 + - xorg-xproto=7.0.31=h7f98852_1007 + - xz=5.2.6=h166bdaf_0 + - zlib=1.2.13=h4ab18f5_6 + - zstandard=0.23.0=py38h62bed22_0 + - zstd=1.5.6=ha6fb4c9_0 + - pip: + - absl-py==2.1.0 + - alabaster==0.7.13 + - anamnesis==1.0.4 + - anyio==4.4.0 + - argon2-cffi==23.1.0 + - argon2-cffi-bindings==21.2.0 + - arrow==1.3.0 + - asttokens==2.4.1 + - astunparse==1.6.3 + - async-lru==2.0.4 + - attrs==23.2.0 + - babel==2.15.0 + - backcall==0.2.0 + - beautifulsoup4==4.12.3 + - bleach==6.1.0 + - bokeh==3.1.1 + - bounded-pool-executor==0.0.3 + - cachetools==5.4.0 + - click==8.1.7 + - cloudpickle==3.0.0 + - comm==0.2.2 + - contourpy==1.1.1 + - cycler==0.12.1 + - dask==2023.3.2 + - debugpy==1.8.2 + - decorator==5.1.1 + - defusedxml==0.7.1 + - dill==0.3.8 + - distributed==2023.3.2 + - dm-tree==0.1.8 + - docutils==0.20.1 + - exceptiongroup==1.2.2 + - executing==2.0.1 + - fastjsonschema==2.20.0 + - flatbuffers==24.3.25 + - fonttools==4.53.1 + - fqdn==1.5.1 + - fslpy==3.11.3 + - fsspec==2024.6.1 + - gast==0.4.0 + - glmtools==0.2.1 + - google-auth==2.32.0 + - google-auth-oauthlib==0.4.6 + - google-pasta==0.2.0 + - grpcio==1.65.1 + - h11==0.14.0 + - h5io==0.1.7 + - h5py==3.11.0 + - httpcore==1.0.5 + - httpx==0.27.0 + - imagesize==1.4.1 + - importlib-metadata==4.13.0 + - importlib-resources==6.4.0 + - ipycanvas==0.13.2 + - ipyevents==2.0.1 + - ipykernel==6.29.5 + - ipympl==0.9.3 + - ipython==8.12.3 + - ipython-genutils==0.2.0 + - ipyvtklink==0.2.2 + - ipywidgets==8.0.5 + - isoduration==20.11.0 + - jedi==0.19.1 + - jinja2==3.0.3 + - joblib==1.4.2 + - json5==0.9.25 + - jsonpointer==3.0.0 + - jsonschema==4.23.0 + - jsonschema-specifications==2023.12.1 + - jupyter==1.0.0 + - jupyter-client==8.1.0 + - jupyter-console==6.6.3 + - jupyter-core==5.7.2 + - jupyter-events==0.10.0 + - jupyter-lsp==2.2.5 + - jupyter-server==2.14.2 + - jupyter-server-terminals==0.5.3 + - jupyterlab==4.2.4 + - jupyterlab-pygments==0.3.0 + - jupyterlab-server==2.27.3 + - jupyterlab-widgets==3.0.11 + - keras==2.11.0 + - kiwisolver==1.4.5 + - libclang==18.1.1 + - linkify-it-py==2.0.3 + - llvmlite==0.41.1 + - locket==1.0.0 + - lxml==5.2.2 + - markdown==3.6 + - markdown-it-py==3.0.0 + - markupsafe==2.1.5 + - mat73==0.62 + - matplotlib==3.7.1 + - matplotlib-inline==0.1.7 + - mdit-py-plugins==0.4.1 + - mdurl==0.1.2 + - mistune==3.0.2 + - mne==1.3.1 + - msgpack==1.0.8 + - nbclient==0.10.0 + - nbconvert==7.16.4 + - nbformat==5.10.4 + - nest-asyncio==1.6.0 + - neurokit2==0.2.3 + - nibabel==5.1.0 + - nilearn==0.10.2 + - notebook==7.2.1 + - notebook-shim==0.2.4 + - numba==0.58.0 + - numpy==1.23.5 + - numpydoc==1.7.0 + - oauthlib==3.2.2 + - opencv-python==4.7.0.72 + - opt-einsum==3.3.0 + - osfclient==0.0.5 + - overrides==7.7.0 + - pandas==1.5.3 + - pandocfilters==1.5.1 + - panel==1.2.3 + - param==2.1.1 + - parse==1.19.0 + - parso==0.8.4 + - partd==1.4.1 + - pexpect==4.9.0 + - pickleshare==0.7.5 + - pkgutil-resolve-name==1.3.10 + - pqdm==0.2.0 + - prometheus-client==0.20.0 + - prompt-toolkit==3.0.47 + - protobuf==3.19.6 + - psutil==6.0.0 + - ptyprocess==0.7.0 + - pure-eval==0.2.3 + - pyasn1==0.6.0 + - pyasn1-modules==0.4.0 + - pygments==2.18.0 + - pyparsing==3.1.2 + - python-dateutil==2.9.0.post0 + - python-json-logger==2.0.7 + - pytz==2024.1 + - pyviz-comms==3.0.2 + - pyyaml==6.0.1 + - pyzmq==26.0.3 + - qtconsole==5.5.2 + - qtpy==2.4.1 + - referencing==0.35.1 + - requests-oauthlib==2.0.0 + - rfc3339-validator==0.1.4 + - rfc3986-validator==0.1.1 + - rpds-py==0.19.0 + - rsa==4.9 + - sails==1.6.0 + - scikit-learn==1.3.1 + - scipy==1.10.1 + - seaborn==0.13.0 + - send2trash==1.8.3 + - six==1.16.0 + - sniffio==1.3.1 + - snowballstemmer==2.2.0 + - sortedcontainers==2.4.0 + - soupsieve==2.5 + - sphinx==7.1.2 + - sphinx-rtd-theme==2.0.0 + - sphinxcontrib-applehelp==1.0.4 + - sphinxcontrib-devhelp==1.0.2 + - sphinxcontrib-htmlhelp==2.0.1 + - sphinxcontrib-jquery==4.1 + - sphinxcontrib-jsmath==1.0.1 + - sphinxcontrib-qthelp==1.0.3 + - sphinxcontrib-serializinghtml==1.1.5 + - stack-data==0.6.3 + - tabulate==0.9.0 + - tblib==3.0.0 + - tensorboard==2.11.2 + - tensorboard-data-server==0.6.1 + - tensorboard-plugin-wit==1.8.1 + - tensorflow==2.11.0 + - tensorflow-estimator==2.11.0 + - tensorflow-io-gcs-filesystem==0.34.0 + - tensorflow-probability==0.19.0 + - termcolor==2.4.0 + - terminado==0.18.1 + - threadpoolctl==3.5.0 + - tinycss2==1.3.0 + - tomli==2.0.1 + - toolz==0.12.1 + - tornado==6.4.1 + - tqdm==4.66.1 + - traitlets==5.14.3 + - types-python-dateutil==2.9.0.20240316 + - uc-micro-py==1.0.3 + - uri-template==1.3.0 + - wcwidth==0.2.13 + - webcolors==24.6.0 + - webencodings==0.5.1 + - websocket-client==1.8.0 + - werkzeug==3.0.3 + - widgetsnbextension==4.0.11 + - wrapt==1.16.0 + - xyzservices==2024.6.0 + - zict==3.0.0 + - zipp==3.19.2 +prefix: osl-toolbox-paper